├── .gitignore ├── History.md ├── Makefile ├── Readme.md ├── lib └── index.js ├── package.json └── test ├── fixture ├── build │ └── index.html └── src │ └── index.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 2 | 0.2.0 / 2017-07-27 3 | ================== 4 | 5 | * fix(sorting): Fixes the return type being ordered by selector, not position in document (#5) 6 | 7 | 0.1.0 - July 11, 2015 8 | --------------------- 9 | * add `tag` metadata to headings 10 | 11 | 0.0.1 - April 2, 2014 12 | --------------------- 13 | :sparkles: -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | node_modules: package.json 3 | @npm install 4 | 5 | test: node_modules 6 | @./node_modules/.bin/mocha --reporter spec 7 | 8 | .PHONY: test -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | 2 | # metalsmith-headings 3 | 4 | A Metalsmith plugin that extracts headings from HTML files and attaches them to the file's metadata. 5 | 6 | ## Installation 7 | 8 | $ npm install metalsmith-headings 9 | 10 | ## Example 11 | 12 | ```js 13 | var Metalsmith = require('metalsmith'); 14 | var headings = require('metalsmith-headings'); 15 | 16 | Metalsmith(__dirname) 17 | .use(headings('h2')) 18 | .build(); 19 | ``` 20 | 21 | ## License 22 | 23 | MIT -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | 2 | var cheerio = require('cheerio'); 3 | var extname = require('path').extname; 4 | 5 | /** 6 | * Expose `plugin`. 7 | */ 8 | 9 | module.exports = plugin; 10 | 11 | /** 12 | * Get the headings from any html files. 13 | * 14 | * @param {String or Object} options (optional) 15 | * @property {Array} selectors 16 | */ 17 | 18 | function plugin(options){ 19 | if ('string' == typeof options) options = { selectors: [options] }; 20 | options = options || {}; 21 | var selectors = options.selectors || ['h2']; 22 | 23 | return function(files, metalsmith, done){ 24 | setImmediate(done); 25 | Object.keys(files).forEach(function(file){ 26 | if ('.html' != extname(file)) return; 27 | var data = files[file]; 28 | var contents = data.contents.toString(); 29 | var $ = cheerio.load(contents); 30 | data.headings = []; 31 | 32 | $(selectors.join(',')).each(function(){ 33 | data.headings.push({ 34 | id: $(this).attr('id'), 35 | tag: $(this)[0].name, 36 | text: $(this).text() 37 | }); 38 | }); 39 | }); 40 | }; 41 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "metalsmith-headings", 3 | "description": "A Metalsmith plugin that extracts headings from HTML files and attaches them to the file's metadata.", 4 | "repository": "git://github.com/segmentio/metalsmith-headings.git", 5 | "version": "0.2.0", 6 | "license": "MIT", 7 | "main": "lib/index.js", 8 | "scripts": { 9 | "test": "mocha --reporter spec" 10 | }, 11 | "dependencies": { 12 | "cheerio": "^0.14.0" 13 | }, 14 | "devDependencies": { 15 | "mocha": "1.x", 16 | "metalsmith": "0.x", 17 | "metalsmith-markdown": "^0.2.1" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/fixture/build/index.html: -------------------------------------------------------------------------------- 1 |

one one

2 |

two one

3 |

one two

4 |

two two

5 |

three

6 | -------------------------------------------------------------------------------- /test/fixture/src/index.md: -------------------------------------------------------------------------------- 1 | 2 | # one one 3 | 4 | ## two one 5 | 6 | # one two 7 | 8 | ## two two 9 | 10 | ### three -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | 2 | var assert = require('assert'); 3 | var Metalsmith = require('metalsmith'); 4 | var markdown = require('metalsmith-markdown'); 5 | var headings = require('..'); 6 | 7 | describe('metalsmith-headings', function(){ 8 | it('should parse headings from HTML', function(done){ 9 | Metalsmith('test/fixture') 10 | .use(markdown()) 11 | .use(headings({ selectors: ['h2'] })) 12 | .build(function(err, files){ 13 | if (err) return done(err); 14 | assert.deepEqual(files['index.html'].headings, [ 15 | { id: 'two-one', tag: 'h2', text: 'two one' }, 16 | { id: 'two-two', tag: 'h2', text: 'two two' } 17 | ]); 18 | done(); 19 | }); 20 | }); 21 | 22 | it('should accept a string shorthand', function(done){ 23 | Metalsmith('test/fixture') 24 | .use(markdown()) 25 | .use(headings('h2')) 26 | .build(function(err, files){ 27 | if (err) return done(err); 28 | assert.deepEqual(files['index.html'].headings, [ 29 | { id: 'two-one', tag: 'h2', text: 'two one' }, 30 | { id: 'two-two', tag: 'h2', text: 'two two' } 31 | ]); 32 | done(); 33 | }); 34 | }); 35 | 36 | it('should preserve order with multiple selectors', function(done){ 37 | Metalsmith('test/fixture') 38 | .use(markdown()) 39 | .use(headings({ selectors: ['h1', 'h2']})) 40 | .build(function(err, files){ 41 | if (err) return done(err); 42 | assert.deepEqual(files['index.html'].headings, [ 43 | { id: 'one-one', tag: 'h1', text: 'one one' }, 44 | { id: 'two-one', tag: 'h2', text: 'two one' }, 45 | { id: 'one-two', tag: 'h1', text: 'one two' }, 46 | { id: 'two-two', tag: 'h2', text: 'two two' } 47 | ]); 48 | done(); 49 | }); 50 | }); 51 | }); 52 | --------------------------------------------------------------------------------