UNPKG

3.95 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.streamToPromise = exports.SitemapStream = exports.closetag = exports.stylesheetInclude = void 0;
4const url_1 = require("url");
5const stream_1 = require("stream");
6const types_1 = require("./types");
7const utils_1 = require("./utils");
8const sitemap_item_stream_1 = require("./sitemap-item-stream");
9const errors_1 = require("./errors");
10const xmlDec = '<?xml version="1.0" encoding="UTF-8"?>';
11const stylesheetInclude = (url) => {
12 // Throws if url is invalid
13 new url_1.URL(url);
14 return `<?xml-stylesheet type="text/xsl" href="${url}"?>`;
15};
16exports.stylesheetInclude = stylesheetInclude;
17const urlsetTagStart = '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"';
18const getURLSetNs = ({ news, video, image, xhtml, custom }, xslURL) => {
19 let ns = xmlDec;
20 if (xslURL) {
21 ns += exports.stylesheetInclude(xslURL);
22 }
23 ns += urlsetTagStart;
24 if (news) {
25 ns += ' xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"';
26 }
27 if (xhtml) {
28 ns += ' xmlns:xhtml="http://www.w3.org/1999/xhtml"';
29 }
30 if (image) {
31 ns += ' xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"';
32 }
33 if (video) {
34 ns += ' xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"';
35 }
36 if (custom) {
37 ns += ' ' + custom.join(' ');
38 }
39 return ns + '>';
40};
41exports.closetag = '</urlset>';
42const defaultXMLNS = {
43 news: true,
44 xhtml: true,
45 image: true,
46 video: true,
47};
48const defaultStreamOpts = {
49 xmlns: defaultXMLNS,
50};
51/**
52 * A [Transform](https://nodejs.org/api/stream.html#stream_implementing_a_transform_stream)
53 * for turning a
54 * [Readable stream](https://nodejs.org/api/stream.html#stream_readable_streams)
55 * of either [SitemapItemOptions](#sitemap-item-options) or url strings into a
56 * Sitemap. The readable stream it transforms **must** be in object mode.
57 */
58class SitemapStream extends stream_1.Transform {
59 constructor(opts = defaultStreamOpts) {
60 opts.objectMode = true;
61 super(opts);
62 this.hasHeadOutput = false;
63 this.hostname = opts.hostname;
64 this.level = opts.level || types_1.ErrorLevel.WARN;
65 this.errorHandler = opts.errorHandler;
66 this.smiStream = new sitemap_item_stream_1.SitemapItemStream({ level: opts.level });
67 this.smiStream.on('data', (data) => this.push(data));
68 this.lastmodDateOnly = opts.lastmodDateOnly || false;
69 this.xmlNS = opts.xmlns || defaultXMLNS;
70 this.xslUrl = opts.xslUrl;
71 }
72 _transform(item, encoding, callback) {
73 if (!this.hasHeadOutput) {
74 this.hasHeadOutput = true;
75 this.push(getURLSetNs(this.xmlNS, this.xslUrl));
76 }
77 this.smiStream.write(utils_1.validateSMIOptions(utils_1.normalizeURL(item, this.hostname, this.lastmodDateOnly), this.level, this.errorHandler));
78 callback();
79 }
80 _flush(cb) {
81 if (!this.hasHeadOutput) {
82 cb(new errors_1.EmptySitemap());
83 }
84 else {
85 this.push(exports.closetag);
86 cb();
87 }
88 }
89}
90exports.SitemapStream = SitemapStream;
91/**
92 * Takes a stream returns a promise that resolves when stream emits finish
93 * @param stream what you want wrapped in a promise
94 */
95function streamToPromise(stream) {
96 return new Promise((resolve, reject) => {
97 const drain = [];
98 stream
99 .pipe(new stream_1.Writable({
100 write(chunk, enc, next) {
101 drain.push(chunk);
102 next();
103 },
104 }))
105 .on('error', reject)
106 .on('finish', () => {
107 if (!drain.length) {
108 reject(new errors_1.EmptyStream());
109 }
110 else {
111 resolve(Buffer.concat(drain));
112 }
113 });
114 });
115}
116exports.streamToPromise = streamToPromise;