-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
120 lines (104 loc) · 2.96 KB
/
index.js
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
'use strict';
const h = require('highland'),
xml = require('xml'),
format = require('date-fns/format');
let log = require('./lib/log').setup({ file: __filename });
/**
* Add the meta tags around the feed
*
* @param {String} title
* @param {String} description
* @param {String} link
* @param {String|Number} [copyright]
* @param {String} [generator]
* @param {String} [docs]
* @param {String} [opt]
* @return {Array}
*/
function feedMetaTags({ title, description, link, copyright, generator, opt }) {
return (group) => {
if (!title || !description || !link) {
throw new Error('A `title`, `description` and `link` property are all required in the `meta` object for the Atom renderer');
}
const now = new Date();
let siteMeta = [
{ id: link.includes('http') ? link : `http://${link}` },
{ title },
{ subtitle: description },
{ link: { _attr: { rel: 'self', href: link } } },
{ updated: format(now, 'YYYY-MM-DDTHH:mm:ssZ') }, // Date format must be RFC 3339 compliant
{ rights: copyright || now.getFullYear() },
{ generator: generator || 'Feed delivered by Clay' },
];
if (opt) {
siteMeta = siteMeta.concat(opt);
}
return siteMeta.concat(group);
};
}
/**
* Sends error to the log service
* @param {Object} res
* @param {Error} e
* @param {string} message
*/
function sendError(res, e, message = e.message) {
const status = 500;
res.status(status);
res.json({ status, message });
log('error', e.message, {
stack: e.stack
});
}
/**
* Wraps content in top level ATOM tags
*
* @param {Array} data
* @param {Object} attr
* @return {Object}
*/
function wrapInTopLevel(data) {
const defaultNamespaces = {
xmlns: 'http://www.w3.org/2005/Atom',
'xmlns:media': 'http://search.yahoo.com/mrss/',
'xmlns:mi': 'http://schemas.ingestion.microsoft.com/common/',
'xmlns:dcterms': 'http://purl.org/dc/terms/',
'xmlns:at': 'http://purl.org/atompub/tombstones/1.0',
'xml:lang': 'en-us'
};
return [{
feed: [{ _attr: { ...defaultNamespaces } }, ...data]
}];
}
/**
* Wrap each item in an object under the `entry` property
*
* @param {Object} item
* @return {Object}
*/
function wrapInEntry(item) {
return { entry: item };
}
function render({ feed, meta }, options, res) {
return h(feed)
.map(wrapInEntry)
.collect()
.map(feedMetaTags(meta))
.map(data => wrapInTopLevel(data))
.errors(e => sendError(res, e))
.toPromise(Promise)
.then(data => {
if (!data) {
throw new Error('No data send to XML renderer, cannot respond');
}
res.type('application/atom+xml');
res.send(xml(data, { declaration: true, indent: '\t' }));
})
.catch(e => sendError(res, e));
}
module.exports.render = render;
// Exported for testing
module.exports.wrapInEntry = wrapInEntry;
module.exports.feedMetaTags = feedMetaTags;
module.exports.wrapInTopLevel = wrapInTopLevel;
module.exports.setLog = (fake) => log = fake;