diff --git a/src/main.ts b/src/main.ts index 46351bf..aa5637c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,8 +1,7 @@ -import fs from 'fs' import { URL } from 'url' import path from 'path' import * as utils from './utils' -import { Options, UrlObj } from './types' +import { Options, UrlObj, FullOptions } from './types' // src: src/sitemap.xsl const xmlStylesheet = Buffer.from('PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjx4c2w6c3R5bGVzaGVldCB4bWxuczp4c2w9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvWFNML1RyYW5zZm9ybSIgeG1sbnM6c2l0ZW1hcD0iaHR0cDovL3d3dy5zaXRlbWFwcy5vcmcvc2NoZW1hcy9zaXRlbWFwLzAuOSIgeG1sbnM6Zm49Imh0dHA6Ly93d3cudzMub3JnLzIwMDUvMDIveHBhdGgtZnVuY3Rpb25zIiB2ZXJzaW9uPSIxLjAiPjx4c2w6dGVtcGxhdGUgbWF0Y2g9Ii8iPjxodG1sPjxoZWFkPjx0aXRsZT5TaXRlbWFwPC90aXRsZT48bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoLCBpbml0aWFsLXNjYWxlPTEsIG1heGltdW0tc2NhbGU9MSwgc2hyaW5rLXRvLWZpdD1ubyIvPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoJCSAJCS5hLW5vLXVsOjpiZWZvcmUgew0KCQkgCQkJZGlzcGxheTogbm9uZTsNCgkJIAkJfQ0KCQkJPC9zdHlsZT48IS0tIE1EVUkgQ1NTIC0tPjxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L25wbS9tZHVpQDEuMC4xL2Rpc3QvY3NzL21kdWkubWluLmNzcyIgaW50ZWdyaXR5PSJzaGEzODQtY0xSck1xMzlIT1pkdkUwajZ5Qm9qTzQrMVBySGZCN2E5bDVxTGNtUm0vZmlXWFlZK0NuZEpQbXl1NUZWLzlUdyIgY3Jvc3NvcmlnaW49ImFub255bW91cyIvPjwvaGVhZD48Ym9keT48ZGl2IGNsYXNzPSJtZHVpLWNvbnRhaW5lciBtZHVpLXR5cG8iPjxoMSBzdHlsZT0idGV4dC1hbGlnbjpjZW50ZXIiPlNpdGVtYXA8L2gxPjxkaXYgY2xhc3M9Im1kdWktZGl2aWRlciIvPjx4c2w6aWYgdGVzdD0iY291bnQoc2l0ZW1hcDpzaXRlbWFwaW5kZXgvc2l0ZW1hcDpzaXRlbWFwKSAmbHQ7IDEiPjxhIGhyZWY9InNpdGVtYXAueG1sIiBjbGFzcz0ibWR1aS1idG4gYS1uby11bCI+PGkgY2xhc3M9Im1kdWktaWNvbiBtYXRlcmlhbC1pY29ucyI+7oybPC9pPmJhY2sgdG8gaW5kZXg8L2E+PC94c2w6aWY+PHhzbDppZiB0ZXN0PSJjb3VudChzaXRlbWFwOnNpdGVtYXBpbmRleC9zaXRlbWFwOnNpdGVtYXApICZsdDsgMSI+PHRhYmxlIGNsYXNzPSJtZHVpLXRhYmxlIj48dGhlYWQ+PHRyPjx0aCBzdHlsZT0id2lkdGg6NzAlIj5VUkw8L3RoPjx0aCBzdHlsZT0id2lkdGg6MjAlIj5MYXN0IG1vZGlmaWNhdGlvbiB0aW1lPC90aD48dGggc3R5bGU9IndpZHRoOjUlIj5DaGFuZ2UgZnJlcXVlbmNlPC90aD48dGggc3R5bGU9IndpZHRoOjUlIj5Qcmlvcml0eTwvdGg+PC90cj48L3RoZWFkPjx0Ym9keT48eHNsOmZvci1lYWNoIHNlbGVjdD0ic2l0ZW1hcDp1cmxzZXQvc2l0ZW1hcDp1cmwiPjx0cj48dGQ+PHhzbDp2YXJpYWJsZSBuYW1lPSJsb2NVcmwiPjx4c2w6dmFsdWUtb2Ygc2VsZWN0PSJzaXRlbWFwOmxvYyIvPjwveHNsOnZhcmlhYmxlPjxhIGhyZWY9InskbG9jVXJsfSI+PHhzbDp2YWx1ZS1vZiBzZWxlY3Q9InNpdGVtYXA6bG9jIi8+PC9hPjwvdGQ+PHRkPjx4c2w6dmFsdWUtb2Ygc2VsZWN0PSJzaXRlbWFwOmxhc3Rtb2QiLz48L3RkPjx0ZD48eHNsOnZhbHVlLW9mIHNlbGVjdD0ic2l0ZW1hcDpjaGFuZ2VmcmVxIi8+PC90ZD48dGQ+PHhzbDp2YWx1ZS1vZiBzZWxlY3Q9InNpdGVtYXA6cHJpb3JpdHkiLz48L3RkPjwvdHI+PC94c2w6Zm9yLWVhY2g+PC90Ym9keT48L3RhYmxlPjwveHNsOmlmPjx4c2w6aWYgdGVzdD0iY291bnQoc2l0ZW1hcDpzaXRlbWFwaW5kZXgvc2l0ZW1hcDpzaXRlbWFwKSAmZ3Q7IDAiPjx0YWJsZSBjbGFzcz0ibWR1aS10YWJsZSI+PHRoZWFkPjx0cj48dGggc3R5bGU9IndpZHRoOjgwJSI+VVJMPC90aD48dGggc3R5bGU9IndpZHRoOjIwJSI+TGFzdCBtb2RpZmljYXRpb24gdGltZTwvdGg+PC90cj48L3RoZWFkPjx0Ym9keT48eHNsOmZvci1lYWNoIHNlbGVjdD0ic2l0ZW1hcDpzaXRlbWFwaW5kZXgvc2l0ZW1hcDpzaXRlbWFwIj48dHI+PHRkPjx4c2w6dmFyaWFibGUgbmFtZT0ibG9jVXJsIj48eHNsOnZhbHVlLW9mIHNlbGVjdD0ic2l0ZW1hcDpsb2MiLz48L3hzbDp2YXJpYWJsZT48YSBocmVmPSJ7JGxvY1VybH0iPjx4c2w6dmFsdWUtb2Ygc2VsZWN0PSJzaXRlbWFwOmxvYyIvPjwvYT48L3RkPjx0ZD48eHNsOnZhbHVlLW9mIHNlbGVjdD0ic2l0ZW1hcDpsYXN0bW9kIi8+PC90ZD48L3RyPjwveHNsOmZvci1lYWNoPjwvdGJvZHk+PC90YWJsZT48L3hzbDppZj48L2Rpdj48IS0tIE1EVUkgSmF2YVNjcmlwdCAtLT48c2NyaXB0IHNyYz0iaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L25wbS9tZHVpQDEuMC4xL2Rpc3QvanMvbWR1aS5taW4uanMiIGludGVncml0eT0ic2hhMzg0LWdDTVpjc2hZS09HUlg5cjZ3YkRydkYrVGNDQ3N3U0hGdWNVelVQd2thK0dyK3VIZ2psWXZrQUJyOTVUQ096M0EiIGNyb3Nzb3JpZ2luPSJhbm9ueW1vdXMiLz48L2JvZHk+PC9odG1sPjwveHNsOnRlbXBsYXRlPjwveHNsOnN0eWxlc2hlZXQ+DQo=', 'base64').toString() @@ -15,6 +14,7 @@ class SitemapManager { [category: string]: string } = {} + #urls: Set = new Set() #isFinished: Boolean = false constructor (options: Options) { @@ -33,7 +33,12 @@ class SitemapManager { if (this.#isFinished) { throw new Error('[SitemapManager] Error: Lifecycle finished') } if (!Array.isArray(url)) url = [url] url.forEach((value) => { - this.#urlDatas[category] = this.#urlDatas[category] + `${utils.objToString(value)}` + if (!this.#urls.has(value.loc.toString())) { + this.#urls.add(value.loc.toString()) + } else { + this.options.hooks.warningHandler(`Url ${value.loc.toString()} is repeated.`) + } + this.#urlDatas[category] = this.#urlDatas[category] + `${utils.objToString(value, this.options.hooks.warningHandler)}` }) } @@ -45,7 +50,14 @@ class SitemapManager { // Create index sitemap let xmlContents = '' for (const category in this.#urlDatas) { - xmlContents = xmlContents + `${utils.objToString({ loc: new URL(path.join(this.options.pathPrefix || '', `sitemap-${category}.xml`), this.options.siteURL), lastmod: new Date() })}` + xmlContents = xmlContents + `${utils.objToString({ + loc: new URL( + path.join(this.options.pathPrefix || '', `sitemap-${category}.xml`), + this.options.siteURL + ), + lastmod: new Date() + }, this.options.hooks.warningHandler) + }` } try { this.options.hooks.fileHandler( @@ -59,7 +71,7 @@ class SitemapManager { // Create each sitemap for (const category in this.#urlDatas) { try { - fs.writeFileSync( + this.options.hooks.fileHandler( path.resolve(this.options?.outDir || './public', `sitemap-${category}.xml`), xmlDeclaration + `${this.#urlDatas[category]}` ) @@ -70,7 +82,7 @@ class SitemapManager { // Create sitemap stylesheet try { - fs.writeFileSync(path.resolve(this.options?.outDir || './public', 'sitemap.xsl'), xmlStylesheet) + this.options.hooks.fileHandler(path.resolve(this.options?.outDir || './public', 'sitemap.xsl'), xmlStylesheet) } catch (e) { reject(new Error(`[SitemapManager]: Failed to write file sitemap.xsl: ${(e as Error).message}`)) } diff --git a/src/utils.ts b/src/utils.ts index d32908a..2ddd09e 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -18,16 +18,23 @@ export function dateConverter (date: Date | string): string { return new Date(date).toISOString() } -export function objToString (url: UrlObj): string { +export function objToString (url: UrlObj, warningHandler: WarningHandler): string { let ele: string ele = `${url.loc.toString()}` if (url.lastmod) { ele = ele + `${new Date(url.lastmod).toISOString()}` } - if (url.priority && url.priority >= 0 && url.priority <= 1) { + if (url.priority) { + if (!(url.priority >= 0 && url.priority <= 1)) { + warningHandler(`The priority of ${url.loc}(${url.priority}) is invalid. Expected value ranges from 0 to 1.`) + } ele = ele + `${url.priority}` } if (url.changefreq) { + if (!((typeof (url.changefreq) === 'number' && url.changefreq >= 1 && url.changefreq <= 7) || + (typeof (url.changefreq) === 'string' && freqMap.indexOf(url.changefreq) > 0))) { + warningHandler(`The changefreq of ${url.loc}(${url.changefreq}) is invalid. Expected a string or a number ranges from 1 to 7. See https://github.com/CBW2007/sitemap-manager/wiki/Types#urlobj`) + } ele = ele + `${(typeof (url.changefreq) === 'number') ? freqMap[url.changefreq] : url.changefreq}` } return ele