Skip to content

Commit

Permalink
(feat) add generate sitemap.txt (#136)
Browse files Browse the repository at this point in the history
* (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)
```

* adjust generate txt and add test code.
testcode: fix generator.js coverage branch coverage 100% and add txt test.

* .txt test code fix

* update README, delete comment out code.
  • Loading branch information
uiolee authored Feb 22, 2022
1 parent 947e5c3 commit 4e89ead
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 42 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
const { extname } = require('path');

hexo.config.sitemap = Object.assign({
path: 'sitemap.xml',
path: ['sitemap.xml', 'sitemap.txt'],
rel: false,
tags: true,
categories: true
}, hexo.config.sitemap);

const config = hexo.config.sitemap;

if (!extname(config.path)) {
if (typeof config.path === 'string' && !extname(config.path)) {
config.path += '.xml';
}

Expand Down
25 changes: 12 additions & 13 deletions lib/generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -33,18 +33,17 @@ 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
};
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 res;
};

function isMatch(path, patterns) {
Expand Down
33 changes: 27 additions & 6 deletions lib/template.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
'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;

const path = config.sitemap.path;
const nunjucks = require('nunjucks');
const env = new nunjucks.Environment(null, {
autoescape: false,
Expand All @@ -23,8 +22,30 @@ module.exports = function(config) {
return input.toISOString().substring(0, 10);
});

const sitemapSrc = config.sitemap.template || join(__dirname, '../sitemap.xml');
sitemapTmpl = nunjucks.compile(readFileSync(sitemapSrc, 'utf8'), env);
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 };
}

return sitemapTmpl;
const res = [];
switch (typeof path) {
case 'string':
res.push(temp(path));
break;
case 'object':
for (const p of path) {
res.push(temp(p));
}
break;
}
return res;
};
5 changes: 5 additions & 0 deletions sitemap.txt
Original file line number Diff line number Diff line change
@@ -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 %}
112 changes: 93 additions & 19 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -31,8 +32,37 @@ 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);
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 = {};

Expand Down Expand Up @@ -60,11 +90,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(),
Expand All @@ -79,7 +109,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'));
Expand All @@ -90,7 +120,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'));
Expand All @@ -99,7 +129,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'));
Expand All @@ -110,7 +140,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'));
Expand All @@ -122,31 +152,49 @@ 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 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);
}
});
});

it('No posts', async () => {
Expand Down Expand Up @@ -252,8 +300,21 @@ 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 = {};
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);

Expand All @@ -263,7 +324,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);
Expand All @@ -278,8 +339,21 @@ 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 = {};
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();
Expand All @@ -288,7 +362,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);
Expand Down

0 comments on commit 4e89ead

Please sign in to comment.