diff --git a/README.md b/README.md index 4a3d0f2..f6f53de 100644 --- a/README.md +++ b/README.md @@ -286,6 +286,12 @@ const default_options = { count: 20, + // optional sorting function for the entries. + // Gets the array entries as the input, expects the sorted array + // as its output. + // e.g.: sort: entries => _.reverse( _.sortBy( entries, 'date' ) ), + sort: entries => entries, + // --------------------------------------------------------------------------- // supported - use in config as needed diff --git a/index.js b/index.js index 99d1845..aa16b14 100644 --- a/index.js +++ b/index.js @@ -36,26 +36,26 @@ const PLUGIN = { */ PLUGIN.get_options_defaults = ( context ) => { - + const { title, description } = context.getSiteData ? context.getSiteData() : context; // --------------------------------------------------------------------------- - + // Feed class options // @see: https://github.com/jpmonette/feed#example - + const feed_options = { - + title, description, generator: PLUGIN.homepage, // ------------------------------------------------------------------------- - - // the following are auto populated in PLUGIN.get_options() + + // the following are auto populated in PLUGIN.get_options() // if they are not set as options /* id, @@ -64,7 +64,7 @@ PLUGIN.get_options_defaults = ( context ) => */ // ------------------------------------------------------------------------- - + // ref: /* title: "Feed Title", @@ -86,30 +86,30 @@ PLUGIN.get_options_defaults = ( context ) => link: "https://example.com/johndoe" } */ - + }; // --------------------------------------------------------------------------- - + const out = { - + // required; it can also be used as enable/disable - + canonical_base: '', // ------------------------------------------------------------------------- - + // Feed class options - + feed_options, // ------------------------------------------------------------------------- - + // @notes: // property name is also the name of the FEED package function - + feeds: { - + rss2: { enable : true, file_name : 'rss.xml', @@ -121,7 +121,7 @@ PLUGIN.get_options_defaults = ( context ) => }, // ----------------------------------------------------------------------- - + atom1: { enable : true, file_name : 'feed.atom', @@ -133,7 +133,7 @@ PLUGIN.get_options_defaults = ( context ) => }, // ----------------------------------------------------------------------- - + json1: { enable : true, file_name : 'feed.json', @@ -143,23 +143,23 @@ PLUGIN.get_options_defaults = ( context ) => title : '%%site_title%% JSON Feed', } }, - + }, // ------------------------------------------------------------------------- - + // order of what gets the highest priority: // // 1. frontmatter // 2. page excerpt // 3. content markdown paragraph // 4. content regular html

- + description_sources: [ - + 'frontmatter', 'excerpt', - + // markdown paragraph regex // @todo: needs work // @@ -167,78 +167,84 @@ PLUGIN.get_options_defaults = ( context ) => // // this excludes blockquotes using `(?!^>)` ///^((?:(?!^#)(?!^\-|\+)(?!^[0-9]+\.)(?!^!\[.*?\]\((.*?)\))(?!^>)(?!^\[\[.*?\]\])(?!^\{\{.*?\}\})[^\n]|\n(?! *\n))+)(?:\n *)+\n/gim, - + // html paragraph regex /(.*?)<\/p>/i, // ----------------------------------------------------------------------- - + // @notes: setting as array require escaping `\` - + //['^((?:(?!^#)(?!^\-|\+)(?!^[0-9]+\.)(?!^\[\[.*?\]\])(?!^\{\{.*?\}\})[^\n]|\n(?! *\n))+)(?:\n *)+\n', 'gim'], //['(.*?)<\/p>', 'i'], - + ], // ------------------------------------------------------------------------- - + // @consider description max words/char // ------------------------------------------------------------------------- - + // order of what gets the highest priority: // // 1. frontmatter // 2. content markdown image such as `![alt text](http://url)` // 3. content regular html img - + image_sources: [ - + 'frontmatter', - + /!\[.*?\]\((.*?)\)/i, // markdown image regex / _.reverse( _.sortBy( entries, 'date' ) ), + sort: entries => entries, // defaults to just returning it as it is + // ------------------------------------------------------------------------- - + // supported - use in config as needed - + // category // contributor - + }; // --------------------------------------------------------------------------- - + return out; - + }; // PLUGIN.get_options_defaults() @@ -249,7 +255,7 @@ PLUGIN.get_options_defaults = ( context ) => */ PLUGIN.get_options = ( plugin_options, context ) => { - + if ( _.isEmpty( PLUGIN.options ) ) { PLUGIN.options = _.defaultsDeep( @@ -258,30 +264,30 @@ PLUGIN.get_options = ( plugin_options, context ) => ); // ------------------------------------------------------------------------- - + // default link and id - + if ( ! PLUGIN.options.feed_options.hasOwnProperty('link') ) { PLUGIN.options.feed_options.link = plugin_options.canonical_base; } - + if ( ! PLUGIN.options.feed_options.hasOwnProperty('id') ) { PLUGIN.options.feed_options.id = plugin_options.canonical_base; } // ------------------------------------------------------------------------- - + // default feedLinks - + if ( ! PLUGIN.options.feed_options.hasOwnProperty('feedLinks') && ! _.isEmpty( PLUGIN.options.feeds ) ) { PLUGIN.options.feed_options.feedLinks = {}; - + const feeds = PLUGIN.options.feeds || {}; - + for ( let key of Object.keys( feeds ) ) { if ( ! PLUGIN.allowed_feed_types.includes( key ) ) @@ -290,39 +296,39 @@ PLUGIN.get_options = ( plugin_options, context ) => } // --------------------------------------------------------------------- - + const url = PLUGIN.get_feed_url( feeds[ key ] ); - + if ( ! url ) { continue; } // --------------------------------------------------------------------- - + key = key.replace(/[0-9]/g, ''); // remove numbers from key; - + PLUGIN.options.feed_options.feedLinks[ key ] = url; } } // ------------------------------------------------------------------------- - + // internal - used in other files/classes - + PLUGIN.options._internal = { name : PLUGIN.name, homepage : PLUGIN.homepage, key : PLUGIN.key, allowed_feed_types: PLUGIN.allowed_feed_types, }; - + } // --------------------------------------------------------------------------- - + return PLUGIN.options; - + }; // PLUGIN.get_options() @@ -333,15 +339,15 @@ PLUGIN.get_options = ( plugin_options, context ) => */ PLUGIN.good_to_go = ( plugin_options, context ) => { - + const options = PLUGIN.get_options( plugin_options, context ); // --------------------------------------------------------------------------- - + return ( options.canonical_base && ! _.isEmpty( options.feeds ) && ! _.isEmpty( PLUGIN.pages ) ); - + }; // PLUGIN.good_to_go() @@ -352,12 +358,12 @@ PLUGIN.good_to_go = ( plugin_options, context ) => */ PLUGIN.get_feed_url = feed => { - + if ( feed.enable && feed.file_name ) { return URL.resolve( PLUGIN.options.canonical_base, feed.file_name ); } - + }; // PLUGIN.get_feed_url() @@ -389,18 +395,18 @@ PLUGIN.is_page_type_post = frontmatter => ( 'post' === PLUGIN.get_page_type( fro */ PLUGIN.is_feed_page = ( page ) => { - + const { frontmatter, path } = page; // --------------------------------------------------------------------------- - + if ( ! _.isEmpty( frontmatter ) ) { // use `frontmatter.feed.enable` to exclude a particular page/post // bailout if it is set to false - + const page_feed_settings = PLUGIN.get_page_feed_settings( frontmatter ); - + /* if ( page_feed_settings.hasOwnProperty('enable') && ! page_feed_settings.enable ) @@ -408,19 +414,19 @@ PLUGIN.is_feed_page = ( page ) => return false; } */ - + // @notes: - // as opposed to the above way of bailing out if set to false - // the following means that any page that has `frontmatter.feed.enable` + // as opposed to the above way of bailing out if set to false + // the following means that any page that has `frontmatter.feed.enable` // set to true will be added - + if ( page_feed_settings.hasOwnProperty('enable') ) { return ( page_feed_settings.enable ); } // ------------------------------------------------------------------------- - + if ( PLUGIN.is_page_type_post( frontmatter ) ) { return true; @@ -428,9 +434,9 @@ PLUGIN.is_feed_page = ( page ) => } // --------------------------------------------------------------------------- - + const directories = PLUGIN.options.posts_directories || []; - + if ( ! _.isEmpty( directories ) ) { for ( const dir of directories ) @@ -443,9 +449,9 @@ PLUGIN.is_feed_page = ( page ) => } // --------------------------------------------------------------------------- - + return false; - + }; // PLUGIN.is_feed_page() @@ -456,68 +462,68 @@ module.exports = ( plugin_options, context ) => ({ /** * used for collecting pages that would be used in feed; * the reason i'm using this, is that `getSiteData` only gets `page.toJson()`, - * which only assigns preperties that don't start with '_' + * which only assigns preperties that don't start with '_' * and what i need is the $page._strippedContent to get content for the feed */ extendPageData ( $page ) { - + try { - + if ( PLUGIN.get_options( plugin_options, context ).is_feed_page( $page ) ) { PLUGIN.pages.push( $page ); } - + } catch ( err ) { - + LIB.LOG.error( err.message ); - + } - + }, // --------------------------------------------------------------------------- - + /** * used for adding head links */ async ready() { - + try { - + if ( PLUGIN.good_to_go( plugin_options, context ) ) { await new LIB.Head( PLUGIN.options, context ).add_links(); } - + } catch ( err ) { - + LIB.LOG.error( err.message ); - + } - + }, // --------------------------------------------------------------------------- - + /** * used for generating the feed files */ async generated ( pagePaths ) { - + try { - + if ( PLUGIN.good_to_go( plugin_options, context ) ) { await new LIB.Generator( PLUGIN.pages, PLUGIN.options, context ).generate(); } - + } catch ( err ) { - + LIB.LOG.error( err.message ); - + } - + } - + }); diff --git a/lib/Generator.js b/lib/Generator.js index 35df5ac..1ffd436 100644 --- a/lib/Generator.js +++ b/lib/Generator.js @@ -31,180 +31,180 @@ const FEED = require('feed').Feed; */ class Generator { - + /** * constructor - * + * * @param {array} pages * @param {object} options * @param {object} context */ constructor( pages, options = {}, context ) { - + if ( _.isEmpty( pages ) ) { throw new Error('pages required'); } - + if ( ! options.canonical_base ) { throw new Error('canonical_base required'); } // ------------------------------------------------------------------------- - + this.pages = pages; // ------------------------------------------------------------------------- - + this.options = options; this.canonical_base = this.options.canonical_base; this.feed_options = this.options.feed_options || {}; this.feeds = this.options.feeds || {}; this._internal = this.options._internal || {}; - + // ------------------------------------------------------------------------- - + this.context = context || {}; - + // ------------------------------------------------------------------------- - + this.feed_generator = new FEED( this.feed_options ); - + } // constructor() - - - + + + /** * @return null */ async add_items() { - + try { - - const pages = this.pages.slice( 0, this.options.count ); - + + const pages = this.options.sort(this.pages).slice( 0, this.options.count ); + LIB.LOG.wait('Adding pages/posts as feed items...'); - + const out = []; - + for ( const page of pages ) { const item = await new LIB.Page( page, this.options, this.context ).get_feed_item(); - + if ( ! _.isEmpty( item ) ) { this.feed_generator.addItem( item ); - + out.push( item ); } } - + // ----------------------------------------------------------------------- - + if ( ! _.isEmpty( out ) ) { LIB.LOG.success(`added ${CHALK.cyan( out.length + ' page(s)' )} as feed item(s)`); } - + // ----------------------------------------------------------------------- - + return out; - + } catch ( err ) { - + LIB.LOG.error( err.message ); - + } - + } // add_items() - - - + + + /** * @return null */ add_categories() { - + try { - + const { category } = this.options; - + if ( category ) { const categories = Array.isArray( category ) ? category : [ category ]; - + categories.map( e => this.feed_generator.addCategory( e ) ); } - + } catch ( err ) { - + LIB.LOG.error( err.message ); - + } - + } // add_categories() - - - + + + /** * @return null */ add_contributors() { - + try { - + const { contributor } = this.options; - + if ( contributor ) { const contributors = Array.isArray( contributor ) ? contributor : [ contributor ]; - + contributors.map( e => this.feed_generator.addContributor( e ) ); } - + } catch ( err ) { - + LIB.LOG.error( err.message ); - + } - + } // add_contributors() - - - + + + /** * @return {array} */ async generate_files() { - + try { - + LIB.LOG.wait('Checking feeds that need to be generated...'); - + if ( _.isEmpty( this.feeds ) ) { LIB.LOG.warn('no feeds set - aborting'); - + return; } - + // ----------------------------------------------------------------------- - + const { outDir, cwd } = this.context; - + const feeds = this.feeds; const out = []; - + for ( const key of Object.keys( feeds ) ) { if ( ! this._internal.allowed_feed_types.includes( key ) ) @@ -213,71 +213,71 @@ class Generator } // --------------------------------------------------------------------- - + const feed = feeds[ key ]; - + if ( ! feed.enable || ! feed.file_name ) { continue; } // --------------------------------------------------------------------- - + const content = this.feed_generator[ key ](); const file = PATH.resolve( outDir, feed.file_name ); const relative = PATH.relative( cwd, file ); - + await FSE.outputFile( file, content ); - + LIB.LOG.success(`${key} feed file generated and saved to ${CHALK.cyan( relative )}`); // --------------------------------------------------------------------- - + out.push( file ); } - + // ----------------------------------------------------------------------- - + return out; - + } catch ( err ) { - + LIB.LOG.error( err.message ); - + } - + } // generate_files() - - - + + + /** * @return {array} */ async generate() { - + try { - + await this.add_items(); - + this.add_categories(); - + this.add_contributors(); - + const files = await this.generate_files(); - + return files; - + } catch ( err ) { - + LIB.LOG.error( err.message ); - + } - + } // generate() - + } // class Generator