tripledoc
Version:
Library to read, create and update documents on a Solid Pod
334 lines • 13.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("./utils");
const fs_1 = require("fs");
const xmlbuilder_1 = require("xmlbuilder");
const errors_1 = require("./errors");
const types_1 = require("./types");
function safeDuration(duration) {
if (duration < 0 || duration > 28800) {
throw new errors_1.InvalidVideoDuration();
}
return duration;
}
const allowDeny = /^allow|deny$/;
const validators = {
'price:currency': /^[A-Z]{3}$/,
'price:type': /^rent|purchase|RENT|PURCHASE$/,
'price:resolution': /^HD|hd|sd|SD$/,
'platform:relationship': allowDeny,
'restriction:relationship': allowDeny
};
function attrBuilder(conf, keys) {
if (typeof keys === 'string') {
keys = [keys];
}
const iv = {};
return keys.reduce((attrs, key) => {
// eslint-disable-next-line
if (conf[key] !== undefined) {
let keyAr = key.split(':');
if (keyAr.length !== 2) {
throw new errors_1.InvalidAttr(key);
}
// eslint-disable-next-line
if (validators[key] && !validators[key].test(conf[key])) {
throw new errors_1.InvalidAttrValue(key, conf[key], validators[key]);
}
attrs[keyAr[1]] = conf[key];
}
return attrs;
}, iv);
}
/**
* Item in sitemap
*/
class SitemapItem {
constructor(conf) {
this.conf = conf;
if (!conf) {
throw new errors_1.NoConfigError();
}
if (!conf.url) {
throw new errors_1.NoURLError();
}
const isSafeUrl = conf.safe;
// URL of the page
this.loc = conf.url;
let dt;
// If given a file to use for last modified date
if (conf.lastmodfile) {
// console.log('should read stat from file: ' + conf.lastmodfile);
let file = conf.lastmodfile;
let stat = fs_1.statSync(file);
let mtime = stat.mtime;
dt = new Date(mtime);
this.lastmod = utils_1.getTimestampFromDate(dt, conf.lastmodrealtime);
// The date of last modification (YYYY-MM-DD)
}
else if (conf.lastmod) {
// append the timezone offset so that dates are treated as local time.
// Otherwise the Unit tests fail sometimes.
let timezoneOffset = 'UTC-' + (new Date().getTimezoneOffset() / 60) + '00';
timezoneOffset = timezoneOffset.replace('--', '-');
dt = new Date(conf.lastmod + ' ' + timezoneOffset);
this.lastmod = utils_1.getTimestampFromDate(dt, conf.lastmodrealtime);
}
else if (conf.lastmodISO) {
this.lastmod = conf.lastmodISO;
}
// How frequently the page is likely to change
// due to this field is optional no default value is set
// please see: https://www.sitemaps.org/protocol.html
this.changefreq = conf.changefreq;
if (!isSafeUrl && this.changefreq) {
if (types_1.CHANGEFREQ.indexOf(this.changefreq) === -1) {
throw new errors_1.ChangeFreqInvalidError();
}
}
// The priority of this URL relative to other URLs
// due to this field is optional no default value is set
// please see: https://www.sitemaps.org/protocol.html
this.priority = conf.priority;
if (!isSafeUrl && this.priority) {
if (!(this.priority >= 0.0 && this.priority <= 1.0) || typeof this.priority !== 'number') {
throw new errors_1.PriorityInvalidError();
}
}
this.news = conf.news;
this.img = conf.img;
this.links = conf.links;
this.expires = conf.expires;
this.androidLink = conf.androidLink;
this.mobile = conf.mobile;
this.video = conf.video;
this.ampLink = conf.ampLink;
this.root = conf.root || xmlbuilder_1.create('root');
this.url = this.root.element('url');
}
/**
* Create sitemap xml
* @return {String}
*/
toXML() {
return this.toString();
}
buildVideoElement(video) {
const videoxml = this.url.element('video:video');
if (typeof (video) !== 'object' || !video.thumbnail_loc || !video.title || !video.description) {
// has to be an object and include required categories https://support.google.com/webmasters/answer/80471?hl=en&ref_topic=4581190
throw new errors_1.InvalidVideoFormat();
}
if (video.description.length > 2048) {
throw new errors_1.InvalidVideoDescription();
}
videoxml.element('video:thumbnail_loc', video.thumbnail_loc);
videoxml.element('video:title').cdata(video.title);
videoxml.element('video:description').cdata(video.description);
if (video.content_loc) {
videoxml.element('video:content_loc', video.content_loc);
}
if (video.player_loc) {
videoxml.element('video:player_loc', attrBuilder(video, 'player_loc:autoplay'), video.player_loc);
}
if (video.duration) {
videoxml.element('video:duration', safeDuration(video.duration));
}
if (video.expiration_date) {
videoxml.element('video:expiration_date', video.expiration_date);
}
if (video.rating) {
videoxml.element('video:rating', video.rating);
}
if (video.view_count) {
videoxml.element('video:view_count', video.view_count);
}
if (video.publication_date) {
videoxml.element('video:publication_date', video.publication_date);
}
if (video.family_friendly) {
videoxml.element('video:family_friendly', video.family_friendly);
}
if (video.tag) {
if (!Array.isArray(video.tag)) {
videoxml.element('video:tag', video.tag);
}
else {
for (const tag of video.tag) {
videoxml.element('video:tag', tag);
}
}
}
if (video.category) {
videoxml.element('video:category', video.category);
}
if (video.restriction) {
videoxml.element('video:restriction', attrBuilder(video, 'restriction:relationship'), video.restriction);
}
if (video.gallery_loc) {
videoxml.element('video:gallery_loc', { title: video['gallery_loc:title'] }, video.gallery_loc);
}
if (video.price) {
videoxml.element('video:price', attrBuilder(video, ['price:resolution', 'price:currency', 'price:type']), video.price);
}
if (video.requires_subscription) {
videoxml.element('video:requires_subscription', video.requires_subscription);
}
if (video.uploader) {
videoxml.element('video:uploader', video.uploader);
}
if (video.platform) {
videoxml.element('video:platform', attrBuilder(video, 'platform:relationship'), video.platform);
}
if (video.live) {
videoxml.element('video:live', video.live);
}
}
buildXML() {
this.url.children = [];
// @ts-ignore
this.url.attribs = {};
// xml property
const props = ['loc', 'lastmod', 'changefreq', 'priority', 'img', 'video', 'links', 'expires', 'androidLink', 'mobile', 'news', 'ampLink'];
// property array size (for loop)
let ps = 0;
// current property name (for loop)
let p;
while (ps < props.length) {
p = props[ps];
ps++;
if (this.img && p === 'img') {
// Image handling
if (!Array.isArray(this.img)) {
// make it an array
this.img = [this.img];
}
this.img.forEach((image) => {
const xmlObj = {};
if (typeof (image) !== 'object') {
// it’s a string
// make it an object
image = { url: image };
}
xmlObj['image:loc'] = image.url;
if (image.caption) {
xmlObj['image:caption'] = { '#cdata': image.caption };
}
if (image.geoLocation) {
xmlObj['image:geo_location'] = image.geoLocation;
}
if (image.title) {
xmlObj['image:title'] = { '#cdata': image.title };
}
if (image.license) {
xmlObj['image:license'] = image.license;
}
this.url.element({ 'image:image': xmlObj });
});
}
else if (this.video && p === 'video') {
// Image handling
if (!Array.isArray(this.video)) {
// make it an array
this.video = [this.video];
}
this.video.forEach(this.buildVideoElement, this);
}
else if (this.links && p === 'links') {
this.links.forEach((link) => {
this.url.element({ 'xhtml:link': {
'@rel': 'alternate',
'@hreflang': link.lang,
'@href': link.url
} });
});
}
else if (this.expires && p === 'expires') {
this.url.element('expires', new Date(this.expires).toISOString());
}
else if (this.androidLink && p === 'androidLink') {
this.url.element('xhtml:link', { rel: 'alternate', href: this.androidLink });
}
else if (this.mobile && p === 'mobile') {
const mobileitem = this.url.element('mobile:mobile');
if (typeof this.mobile === 'string') {
mobileitem.att('type', this.mobile);
}
}
else if (this.priority !== undefined && p === 'priority') {
if (this.conf.fullPrecisionPriority) {
this.url.element(p, this.priority + '');
}
else {
this.url.element(p, parseFloat(this.priority + '').toFixed(1));
}
}
else if (this.ampLink && p === 'ampLink') {
this.url.element('xhtml:link', { rel: 'amphtml', href: this.ampLink });
}
else if (this.news && p === 'news') {
let newsitem = this.url.element('news:news');
if (!this.news.publication ||
!this.news.publication.name ||
!this.news.publication.language ||
!this.news.publication_date ||
!this.news.title) {
throw new errors_1.InvalidNewsFormat();
}
if (this.news.publication) {
let publication = newsitem.element('news:publication');
if (this.news.publication.name) {
publication.element('news:name').cdata(this.news.publication.name);
}
if (this.news.publication.language) {
publication.element('news:language', this.news.publication.language);
}
}
if (this.news.access) {
if (this.news.access !== 'Registration' &&
this.news.access !== 'Subscription') {
throw new errors_1.InvalidNewsAccessValue();
}
newsitem.element('news:access', this.news.access);
}
if (this.news.genres) {
newsitem.element('news:genres', this.news.genres);
}
newsitem.element('news:publication_date', this.news.publication_date);
newsitem.element('news:title').cdata(this.news.title);
if (this.news.keywords) {
newsitem.element('news:keywords', this.news.keywords);
}
if (this.news.stock_tickers) {
newsitem.element('news:stock_tickers', this.news.stock_tickers);
}
}
else if (this.loc && p === 'loc' && this.conf.cdata) {
this.url.element({
loc: {
'#raw': this.loc
}
});
}
else if (this.loc && p === 'loc') {
this.url.element(p, this.loc);
}
else if (this.changefreq && p === 'changefreq') {
this.url.element(p, this.changefreq);
}
else if (this.lastmod && p === 'lastmod') {
this.url.element(p, this.lastmod);
}
}
return this.url;
}
/**
* Alias for toXML()
* @return {String}
*/
toString() {
return this.buildXML().toString();
}
}
exports.default = SitemapItem;
//# sourceMappingURL=sitemap-item.js.map