From 0b2025a38d0a0506cb5f0886796679b32baa65e8 Mon Sep 17 00:00:00 2001 From: uiolee <22849383+uiolee@users.noreply.github.com> Date: Sat, 12 Feb 2022 15:48:27 +0800 Subject: [PATCH 1/4] (feat) add generate `sitemap.txt` - default generate `sitemap.txt` and `sitemap.xml` - `generator.js` judge `path` string or array - `template.js` `extname(path)` to chose template ``` sitemap: path: - sitemap.xml - sitemap.txt #remove it to disable template_txt: sitemap.txt #(optional) ``` --- index.js | 4 ++-- lib/generator.js | 35 +++++++++++++++++++++++------------ lib/template.js | 18 ++++++++++++------ sitemap.txt | 5 +++++ 4 files changed, 42 insertions(+), 20 deletions(-) create mode 100644 sitemap.txt diff --git a/index.js b/index.js index 3e99d77..75b3381 100644 --- a/index.js +++ b/index.js @@ -4,7 +4,7 @@ const { extname } = require('path'); hexo.config.sitemap = Object.assign({ - path: 'sitemap.xml', + path: ['sitemap.xml', 'sitemap.txt'], rel: false, tags: true, categories: true @@ -12,7 +12,7 @@ hexo.config.sitemap = Object.assign({ const config = hexo.config.sitemap; -if (!extname(config.path)) { +if (typeof config.path === 'string' && !extname(config.path)) { config.path += '.xml'; } diff --git a/lib/generator.js b/lib/generator.js index ae71a01..eaf8327 100644 --- a/lib/generator.js +++ b/lib/generator.js @@ -33,18 +33,29 @@ module.exports = function(locals) { return; } - const data = template(config).render({ - config, - posts, - sNow: new Date(), - tags: tagsCfg ? locals.tags.toArray() : [], - categories: catsCfg ? locals.categories.toArray() : [] - }); - - return { - path, - data - }; + function rend(config) { + const d = template(config).render({ + config, + posts, + sNow: new Date(), + tags: tagsCfg ? locals.tags.toArray() : [], + categories: catsCfg ? locals.categories.toArray() : [] + }); + return d; + } + let res = []; + switch (typeof path) { + case 'string': + res = { path: path, data: rend(config) }; + break; + case 'object': + for (const x of path) { + config.sitemap.path = x; + res.push({ path: x, data: rend(config) }); + } + break; + } + return res; }; function isMatch(path, patterns) { diff --git a/lib/template.js b/lib/template.js index bc0e101..b13e54e 100644 --- a/lib/template.js +++ b/lib/template.js @@ -1,13 +1,13 @@ 'use strict'; -const { join } = require('path'); +const { join, extname } = require('path'); const { readFileSync } = require('fs'); let sitemapTmpl; const { encodeURL } = require('hexo-util'); module.exports = function(config) { - if (sitemapTmpl) return sitemapTmpl; - + // if (sitemapTmpl) return sitemapTmpl; + const path = config.sitemap.path; const nunjucks = require('nunjucks'); const env = new nunjucks.Environment(null, { autoescape: false, @@ -22,9 +22,15 @@ module.exports = function(config) { env.addFilter('formatDate', input => { return input.toISOString().substring(0, 10); }); - - const sitemapSrc = config.sitemap.template || join(__dirname, '../sitemap.xml'); + let sitemapSrc; + switch (extname(path)) { + case '.xml': + sitemapSrc = config.sitemap.template || join(__dirname, '../sitemap.xml'); + break; + case '.txt': + sitemapSrc = config.sitemap.template_txt || join(__dirname, '../sitemap.txt'); + break; + } sitemapTmpl = nunjucks.compile(readFileSync(sitemapSrc, 'utf8'), env); - return sitemapTmpl; }; diff --git a/sitemap.txt b/sitemap.txt new file mode 100644 index 0000000..33751c4 --- /dev/null +++ b/sitemap.txt @@ -0,0 +1,5 @@ +{% for post in posts %}{{ post.permalink | uriencode }} +{% endfor %}{{ config.url | uriencode }} +{% for tag in tags %}{{ tag.permalink | uriencode }} +{% endfor %}{% for cat in categories %}{{ cat.permalink | uriencode }} +{% endfor %} \ No newline at end of file From e46780ab93907cc5a5f09cdb5e198d6ab8411955 Mon Sep 17 00:00:00 2001 From: uiolee <22849383+uiolee@users.noreply.github.com> Date: Wed, 16 Feb 2022 11:17:14 +0800 Subject: [PATCH 2/4] adjust generate txt and add test code. testcode: fix generator.js coverage branch coverage 100% and add txt test. --- lib/generator.js | 20 ++------- lib/template.js | 32 +++++++++---- test/index.js | 114 +++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 123 insertions(+), 43 deletions(-) diff --git a/lib/generator.js b/lib/generator.js index eaf8327..fb20d62 100644 --- a/lib/generator.js +++ b/lib/generator.js @@ -6,7 +6,7 @@ const template = require('./template'); module.exports = function(locals) { const { config } = this; const { sitemap, skip_render } = config; - const { path, tags: tagsCfg, categories: catsCfg } = sitemap; + const { tags: tagsCfg, categories: catsCfg } = sitemap; const skipRenderList = [ '**/*.js', '**/*.css' @@ -33,27 +33,15 @@ module.exports = function(locals) { return; } - function rend(config) { - const d = template(config).render({ + const res = template(config); + for (const i in res) { + res[i].data = res[i].data.render({ config, posts, sNow: new Date(), tags: tagsCfg ? locals.tags.toArray() : [], categories: catsCfg ? locals.categories.toArray() : [] }); - return d; - } - let res = []; - switch (typeof path) { - case 'string': - res = { path: path, data: rend(config) }; - break; - case 'object': - for (const x of path) { - config.sitemap.path = x; - res.push({ path: x, data: rend(config) }); - } - break; } return res; }; diff --git a/lib/template.js b/lib/template.js index b13e54e..3f084fd 100644 --- a/lib/template.js +++ b/lib/template.js @@ -22,15 +22,31 @@ module.exports = function(config) { env.addFilter('formatDate', input => { return input.toISOString().substring(0, 10); }); - let sitemapSrc; - switch (extname(path)) { - case '.xml': - sitemapSrc = config.sitemap.template || join(__dirname, '../sitemap.xml'); + + function temp(p) { + let sitemapSrc; + switch (extname(p)) { + case '.xml': + sitemapSrc = config.sitemap.template || join(__dirname, '../sitemap.xml'); + break; + case '.txt': + sitemapSrc = config.sitemap.template_txt || join(__dirname, '../sitemap.txt'); + break; + } + sitemapTmpl = nunjucks.compile(readFileSync(sitemapSrc, 'utf8'), env); + return { path: p, data: sitemapTmpl }; + } + + const res = []; + switch (typeof path) { + case 'string': + res.push(temp(path)); break; - case '.txt': - sitemapSrc = config.sitemap.template_txt || join(__dirname, '../sitemap.txt'); + case 'object': + for (const p of path) { + res.push(temp(p)); + } break; } - sitemapTmpl = nunjucks.compile(readFileSync(sitemapSrc, 'utf8'), env); - return sitemapTmpl; + return res; }; diff --git a/test/index.js b/test/index.js index 0200e3e..cc1d7e3 100644 --- a/test/index.js +++ b/test/index.js @@ -5,8 +5,9 @@ const Hexo = require('hexo'); const cheerio = require('cheerio'); const { deepMerge, encodeURL } = require('hexo-util'); const { transform } = require('camaro'); +const { extname } = require('path'); const sitemapCfg = { - path: 'sitemap.xml', + path: ['sitemap.xml', 'sitemap.txt'], rel: false, tags: true, categories: true @@ -31,8 +32,39 @@ describe('Sitemap generator', () => { const Post = hexo.model('Post'); const Page = hexo.model('Page'); - const generator = require('../lib/generator').bind(hexo); - const sitemapTmpl = require('../lib/template')(hexo.config); + // const generator = require('../lib/generator').bind(hexo); + // const sitemapTmpl = require('../lib/template')(hexo.config); + const templ = require('../lib/template')(hexo.config); + const generator = function(locals) { + const res = require('../lib/generator').bind(hexo)(locals); + const data = {}; + for (const r of res) { + switch (extname(r.path)) { + case '.xml': + data.xml = r; + break; + case '.txt': + data.txt = r; + break; + } + } + return data; + }; + const sitemapTmpl = (function(templ) { + const data = {}; + for (const r of templ) { + switch (extname(r.path)) { + case '.xml': + data.xml = r.data; + break; + case '.txt': + data.txt = r.data; + break; + } + } + return data; + }(templ)); + let posts = []; let locals = {}; @@ -60,11 +92,11 @@ describe('Sitemap generator', () => { }); it('default', async () => { - const result = generator(locals); + const result = generator(locals).xml; const { items } = await p(result.data); result.path.should.eql('sitemap.xml'); - result.data.should.eql(sitemapTmpl.render({ + result.data.should.eql(sitemapTmpl.xml.render({ config: hexo.config, posts, sNow: new Date(), @@ -79,7 +111,7 @@ describe('Sitemap generator', () => { }); it('tags', async () => { - const { data } = generator(locals); + const { data } = generator(locals).xml; const { items } = await p(data); const result = items.filter(({ link }) => link.includes('tags')); @@ -90,7 +122,7 @@ describe('Sitemap generator', () => { it('tags - disable', async () => { hexo.config.sitemap.tags = false; - const { data } = generator(locals); + const { data } = generator(locals).xml; const { items } = await p(data); const result = items.filter(({ link }) => link.includes('tags')); @@ -99,7 +131,7 @@ describe('Sitemap generator', () => { }); it('categories', async () => { - const { data } = generator(locals); + const { data } = generator(locals).xml; const { items } = await p(data); const result = items.filter(({ link }) => link.includes('categories')); @@ -110,7 +142,7 @@ describe('Sitemap generator', () => { it('categories - disable', async () => { hexo.config.sitemap.categories = false; - const { data } = generator(locals); + const { data } = generator(locals).xml; const { items } = await p(data); const result = items.filter(({ link }) => link.includes('categories')); @@ -122,31 +154,47 @@ describe('Sitemap generator', () => { it('array', () => { hexo.config.skip_render = ['foo']; - const result = generator(locals); + const result = generator(locals).xml; result.data.should.not.contain('foo'); }); it('string', () => { hexo.config.skip_render = 'bar'; - const result = generator(locals); + const result = generator(locals).xml; result.data.should.not.contain('bar'); }); + it('string - off', () => { // coverage branch 100% + hexo.config.skip_render = ''; + + const result = generator(locals).xml; + result.should.be.ok; + }); + it('invalid type', () => { hexo.config.skip_render = { foo: 'bar' }; - const result = generator(locals); + const result = generator(locals).xml; result.should.be.ok; }); it('off', () => { hexo.config.skip_render = null; - const result = generator(locals); + const result = generator(locals).xml; result.should.be.ok; }); }); + + it('Sitemap-TXT', () => { + const result = generator(locals).txt; + const items = result.data.split('\r\n'); + result.path.should.eql('sitemap.txt'); + for (let i = 0; i < posts.length; i++) { + items[i].should.eql(posts[i].permalink); + } + }); }); it('No posts', async () => { @@ -252,8 +300,22 @@ describe('IDN', () => { path: 'sitemap.xml' }; const Post = hexo.model('Post'); - const generator = require('../lib/generator').bind(hexo); - + // const generator = require('../lib/generator').bind(hexo); + const generator = function(locals) { + const res = require('../lib/generator').bind(hexo)(locals); + const data = {}; + for (const r of res) { + switch (extname(r.path)) { + case '.xml': + data.xml = r; + break; + case '.txt': + data.txt = r; + break; + } + } + return data; + }; hexo.config.url = 'http://fôo.com/bár'; const parsedUrl = encodeURL(hexo.config.url); @@ -263,7 +325,7 @@ describe('IDN', () => { }); const locals = hexo.locals.toObject(); - const result = generator(locals); + const result = generator(locals).xml; const { items } = await p(result.data); items.forEach(element => { element.link.startsWith(parsedUrl).should.eql(true); @@ -278,8 +340,22 @@ describe('IDN', () => { path: 'sitemap.xml' }; const Post = hexo.model('Post'); - const generator = require('../lib/generator').bind(hexo); - + // const generator = require('../lib/generator').bind(hexo); + const generator = function(locals) { + const res = require('../lib/generator').bind(hexo)(locals); + const data = {}; + for (const r of res) { + switch (extname(r.path)) { + case '.xml': + data.xml = r; + break; + case '.txt': + data.txt = r; + break; + } + } + return data; + }; hexo.config.url = 'http://foo.com/b%C3%A1r'; await hexo.init(); @@ -288,7 +364,7 @@ describe('IDN', () => { }); const locals = hexo.locals.toObject(); - const result = generator(locals); + const result = generator(locals).xml; const { items } = await p(result.data); items.forEach(element => { element.link.startsWith(hexo.config.url).should.eql(true); From c1bc921075b2f9785c1fc74adc4dae1837144bb4 Mon Sep 17 00:00:00 2001 From: uiolee <22849383+uiolee@users.noreply.github.com> Date: Wed, 16 Feb 2022 13:46:37 +0800 Subject: [PATCH 3/4] .txt test code fix --- test/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/index.js b/test/index.js index cc1d7e3..43e4aff 100644 --- a/test/index.js +++ b/test/index.js @@ -189,7 +189,9 @@ describe('Sitemap generator', () => { it('Sitemap-TXT', () => { const result = generator(locals).txt; - const items = result.data.split('\r\n'); + const reg = new RegExp('\\r\\n|\\r|\\n', 'g'); + let items = result.data.replace(reg, '\n'); + items = items.split('\n'); result.path.should.eql('sitemap.txt'); for (let i = 0; i < posts.length; i++) { items[i].should.eql(posts[i].permalink); From be922a381e70fc3cd5b008a0bf6a9abaf9ae0687 Mon Sep 17 00:00:00 2001 From: uiolee <22849383+uiolee@users.noreply.github.com> Date: Sun, 20 Feb 2022 20:35:36 +0800 Subject: [PATCH 4/4] update README, delete comment out code. --- README.md | 8 ++++++-- lib/template.js | 1 - test/index.js | 4 ---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index ce2e591..e938f26 100644 --- a/README.md +++ b/README.md @@ -22,15 +22,19 @@ You can configure this plugin in `_config.yml`. ``` yaml sitemap: - path: sitemap.xml + path: + - sitemap.xml + - sitemap.txt template: ./sitemap_template.xml + template_txt: ./sitemap_template.txt rel: false tags: true categories: true ``` - **path** - Sitemap path. (Default: sitemap.xml) -- **template** - Custom template path. This file will be used to generate sitemap.xml (See [default template](/sitemap.xml)) +- **template** - Custom template path. This file will be used to generate sitemap.xml (See [default xml template](/sitemap.xml)) +- **template_txt** - Custom template path. This file will be used to generate sitemap.txt (See [default txt template](/sitemap.txt)) - **rel** - Add [`rel-sitemap`](http://microformats.org/wiki/rel-sitemap) to the site's header. (Default: `false`) - **tags** - Add site's tags - **categories** - Add site's categories diff --git a/lib/template.js b/lib/template.js index 3f084fd..d5ce388 100644 --- a/lib/template.js +++ b/lib/template.js @@ -6,7 +6,6 @@ let sitemapTmpl; const { encodeURL } = require('hexo-util'); module.exports = function(config) { - // if (sitemapTmpl) return sitemapTmpl; const path = config.sitemap.path; const nunjucks = require('nunjucks'); const env = new nunjucks.Environment(null, { diff --git a/test/index.js b/test/index.js index 43e4aff..8df1f5d 100644 --- a/test/index.js +++ b/test/index.js @@ -32,8 +32,6 @@ describe('Sitemap generator', () => { const Post = hexo.model('Post'); const Page = hexo.model('Page'); - // const generator = require('../lib/generator').bind(hexo); - // const sitemapTmpl = require('../lib/template')(hexo.config); const templ = require('../lib/template')(hexo.config); const generator = function(locals) { const res = require('../lib/generator').bind(hexo)(locals); @@ -302,7 +300,6 @@ describe('IDN', () => { path: 'sitemap.xml' }; const Post = hexo.model('Post'); - // const generator = require('../lib/generator').bind(hexo); const generator = function(locals) { const res = require('../lib/generator').bind(hexo)(locals); const data = {}; @@ -342,7 +339,6 @@ describe('IDN', () => { path: 'sitemap.xml' }; const Post = hexo.model('Post'); - // const generator = require('../lib/generator').bind(hexo); const generator = function(locals) { const res = require('../lib/generator').bind(hexo)(locals); const data = {};