New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

grunt-pages

Package Overview
Dependencies
Maintainers
1
Versions
31
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

grunt-pages - npm Package Compare versions

Comparing version 0.7.2 to 0.8.0

11

package.json
{
"name": "grunt-pages",
"version": "0.7.2",
"version": "0.8.0",
"description": "Grunt task to create pages using markdown and templates",

@@ -11,4 +11,3 @@ "main": "Gruntfile.js",

"pygmentize-bundled": "~2.1.0",
"marked": "git://github.com/ChrisWren/marked.git#40b3f286203ec7013e81d2c6ce03fabf8a4129b0",
"js-yaml": "~2.1.0",
"marked": "git://github.com/ChrisWren/marked.git#listener",
"rss": "~0.2.0",

@@ -23,3 +22,3 @@ "lodash": "~2.0.0"

"grunt-contrib-watch": "~0.4.4",
"grunt-concurrent": "~0.2.0",
"grunt-concurrent": "~0.3.1",
"matchdep": "~0.1.2",

@@ -31,3 +30,5 @@ "grunt-contrib-copy": "~0.4.1",

"grunt-release": "~0.4.0",
"grunt-mdlint": "0.0.0"
"grunt-mdlint": "0.0.0",
"grunt-node-inspector": "~0.1.0",
"grunt-shell": "~0.4.0"
},

@@ -34,0 +35,0 @@ "peerDependencies": {

@@ -9,7 +9,6 @@ # grunt-pages

## Prerequisites
This Grunt task uses [pygments](#syntax-highlighting), which relies on [Python](http://www.python.org/getit/) version `2.7.x`.
> Please note that grunt-pages will **not** run on the `3.x` branch of Python
This Grunt task uses [pygments](http://pygments.org/) which requires [Python](http://www.python.org/getit/) to be installed.
## Getting Started
If you haven't used grunt before, be sure to check out the [Getting Started](http://gruntjs.com/getting-started) guide, as it explains how to create a gruntfile as well as install and use grunt plugins. Once you're familiar with that process, install this plugin with this command:
If you haven't used Grunt before, be sure to check out the [Getting Started](http://gruntjs.com/getting-started) guide, as it explains how to create a Gruntfile as well as install and use Grunt plugins. Once you're familiar with that process, install this plugin with this command:
```shell

@@ -26,2 +25,3 @@ npm install grunt-pages --save-dev

## Documentation
### Sample config

@@ -35,3 +35,3 @@ Here is a sample config to create a blog using grunt-pages:

posts: {
src: 'src/posts',
src: 'posts',
dest: 'dev',

@@ -47,13 +47,4 @@ layout: 'src/layouts/post.jade',

#### Post Format
Posts are written in markdown and include a metadata section at the top to provide information about the post. There are two accepted metadata formats, YAML and a JavaScript object. Here is a YAML example:
```yaml
----
title: The Versace Sofa Thesis Vol. I
date: 2010-10-4
author: Pusha T
----
```
The YAML data is parsed into a JavaScript object and passed to the post's template to be rendered. Check out [js-yaml's site](http://nodeca.github.io/js-yaml/) to learn more about how the translation works.
Posts are written in markdown and include a metadata section at the top to provide information about the post. The metadata format is a JavaScript Object, and here is an example:
Here is a JavaScript object example:
```js

@@ -66,11 +57,13 @@ {

```
The only property that is not interpreted literally is the `date`. It is used as a `dateString` when constructing a [Date object](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date) in JavaScript, and must be in a [parseable format](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/parse). For both YAML and JavaScript object metadata, the JavaScript `Date` object is available in the layout.
The only property that is not interpreted literally is the `date`. It is used as a `dateString` when constructing a [Date object](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date) in JavaScript, and must be in a [parseable format](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/parse).
#### Syntax Highlighting
For adding code to your posts, grunt-pages has [GitHub flavoured markdown](https://help.github.com/articles/github-flavored-markdown) syntax highlighting using [pygments](http://pygments.org/).
For adding code to your posts, grunt-pages has [GitHub flavoured markdown](https://help.github.com/articles/github-flavored-markdown) and syntax highlighting using [pygments](http://pygments.org/).
#### Draft Posts
To make a post a draft, simply prefix its filename with a `_`. These posts will not be rendered or available in list pages.
To make a post a draft when deploying your site, simply prefix its filename with a `_`. These posts will not be rendered or available in list pages.
### Required properties
#### src

@@ -91,6 +84,8 @@ Type: `String`

**Note: you can run grunt-pages with the --debug flag set to see all the data passed to templates for rendering**
#### url
Type: `String`
The url of each post. The url string takes variables as parameters using the `:variable` syntax. Variable(s) specified in the url are required in each post's metadata. Urls ending with a trailing `/` will generate posts as index.html files inside of the url's folder.
The URL of each post. The URL string takes variables as parameters using the `:variable` syntax. Variables specified in the URL are required in each post's metadata. URLs ending with a trailing `/` will generate posts as index.html files inside of the URL's folder.

@@ -102,3 +97,3 @@ ### Options

The folder where the ejs or jade source pages of your website are located. These pages have access to each post's `content` and metadata properties via a `posts` array. Additionally, pages have access to their own filename(without extension) via the `currentPage` variable. All of the files in this folder are generated in the `dest` folder maintaining the same relative path from `pageSrc`.
The folder where the ejs or jade source pages of your website are located. These pages have access to each post's `content` and metadata properties via a `posts` array. Additionally, pages have access to their own filename(without extension) via the `currentPage` variable to optionally display it differently when linking to pages. All of the files in this folder are generated in the `dest` folder maintaining the same relative path from `pageSrc`.

@@ -138,2 +133,3 @@ #### data

```
A function that takes a `url` as a parameter and returns a formatted url string. This is primarily used to remove special characters and replace whitespace.

@@ -161,3 +157,3 @@

posts: {
src: 'src/posts',
src: 'posts',
dest: 'dev',

@@ -211,3 +207,3 @@ layout: 'src/layouts/post.jade',

posts: {
src: 'src/posts',
src: 'posts',
dest: 'dev',

@@ -230,3 +226,3 @@ layout: 'src/layouts/post.jade',

The location of the layout template which is used for each list page. [Here](https://github.com/CabinJS/grunt-pages/blob/master/test/fixtures/integration/input/jade/pages/blog/index.jade) is a sample `listPage` template. This template has access to the following variables:
The location of the layout template which is used for each list page. This page will not be rendered as a regular page if inside the options.pageSrc folder and instead will be rendered as the root list page with the first post group. [Here](https://github.com/CabinJS/grunt-pages/blob/master/test/fixtures/integration/input/jade/pages/blog/index.jade) is a sample `listPage` template. This template has access to the following variables:

@@ -286,4 +282,4 @@ ###### posts

posts: [{
title: 'ES6',
tags: ['javascript'],
title: 'Front end web development',
tags: ['javascript', 'css'],
content: '...'

@@ -301,2 +297,6 @@ }, {

content: '...'
},{
title: 'Front end web development',
tags: ['javascript', 'css'],
content: '...'
}]

@@ -354,2 +354,4 @@ }];

**0.7.2** - Added support for Python 3 due to updating of [node-pygmentize-bundled](https://github.com/rvagg/node-pygmentize-bundled/) dependency.
**0.7.1** - Wrong node_modules were pushed to npm. Pushed correct dependencies listed in package.json to fix bug.

@@ -356,0 +358,0 @@

@@ -15,3 +15,2 @@ /*

require('colors');
var jsYAML = require('js-yaml');
var _ = require('lodash');

@@ -40,3 +39,3 @@ var marked = require('marked');

// Create a reference to the template engine that is available to all lib methods
// Create a reference to the template engine that is available to all library methods
var templateEngine;

@@ -48,5 +47,8 @@

grunt.registerMultiTask('pages', 'Creates pages from markdown and templates.', function () {
// Task is asynchronous due to usage of pygments syntax highlighter written in python
var done = this.async();
// Create a reference to the the context object and task options so that they are available to all lib methods
// Create a reference to the the context object and task options
// so that they are available to all library methods
_this = this;

@@ -76,6 +78,7 @@ options = this.options();

// Start off the parsing with unmodified posts already included
var parsedPosts = unmodifiedPosts.length;
var postCollection = unmodifiedPosts;
// If there are no posts to parse, immediately render the posts and pages
// If none of the posts have been modified, immediately render the posts and pages
if (parsedPosts === numPosts) {

@@ -108,9 +111,20 @@ lib.renderPostsAndPages(postCollection, cacheFile, done);

if (post.markdown.length <= 1) {
grunt.fail.fatal('the following post is blank, please add some content to it or delete it: ' + postpath.red);
grunt.fail.fatal('The following post is blank, please add some content to it or delete it: ' + postpath.red + '.');
}
marked.setOptions({
// Parse post using [marked](https://github.com/chjj/marked)
marked(post.markdown, {
on: _.extend({
heading : function (token, callback) {
callback(null, '<a name="' +
token.text.toLowerCase().replace(/[^\w]+/g, '-') +
'"class="anchor" href="#' +
token.text.toLowerCase().replace(/[^\w]+/g, '-') +
'"><span class="header-link"></span></a>' +
token.text);
}
}, options.listeners || {}),
highlight: function (code, lang, callback) {
// Use [pygments](http://pygments.org/) for highlighting
// Use [pygments](http://pygments.org/) for syntax highlighting
pygmentize({ lang: lang, format: 'html' }, code, function (err, result) {

@@ -122,9 +136,6 @@ callback(err, result.toString());

anchors: true
});
// Parse post using [marked](https://github.com/chjj/marked)
marked(post.markdown, function (err, content) {
}, function (err, content) {
if (err) throw err;
// Replace markdown source with content property
// Replace markdown property with parsed content property
post.content = content;

@@ -144,2 +155,39 @@ delete post.markdown;

/**
* Gets the end of the metadata section to allow for the metadata to be JSON.parsed
* and for the content to be extracted
* @param {String} fileString Contents of entire post
* @param {Number} currentIndex Index delimiting the substring to be searched for {'s and }'s
* @return {String}
*/
lib.getMetadataEnd = function (fileString, currentIndex) {
var curlyNest = 1;
while (curlyNest !== 0 && fileString.substr(currentIndex).length > 0) {
if (fileString.substr(currentIndex).indexOf('}') === -1 &&
fileString.substr(currentIndex).indexOf('{') === -1) {
return false;
}
if (fileString.substr(currentIndex).indexOf('}') !== -1) {
if (fileString.substr(currentIndex).indexOf('{') !== -1) {
if (fileString.substr(currentIndex).indexOf('}') < fileString.substr(currentIndex).indexOf('{')) {
currentIndex += fileString.substr(currentIndex).indexOf('}') + 1;
curlyNest--;
} else {
currentIndex += fileString.substr(currentIndex).indexOf('{') + 1;
curlyNest++;
}
} else {
currentIndex += fileString.substr(currentIndex).indexOf('}') + 1;
curlyNest--;
}
} else {
currentIndex += fileString.substr(currentIndex).indexOf('{') + 1;
curlyNest++;
}
}
return curlyNest === 0 ? currentIndex : false;
};
/**
* Parses the metadata and markdown from a post

@@ -152,24 +200,28 @@ * @param {String} postPath Absolute path of the post to be parsed

var postData = {};
var errMessage = 'The metadata for the following post is formatted incorrectly: ' + postPath.red + '\n' +
'Go to the following link to learn more about post formatting:\n\n' +
'https://github.com/CabinJS/grunt-pages#authoring-posts';
try {
var metaDataStart;
if (fileString.indexOf('{') < fileString.indexOf('}')) {
metaDataStart = fileString.indexOf('{');
} else {
return grunt.fail.fatal(errMessage);
}
// Parse JSON metadata
if (fileString.indexOf('{') === 0) {
postData = eval('(' + fileString.substr(0, fileString.indexOf('\n}') + 2) + ')');
postData.date = new Date(postData.date);
postData.markdown = fileString.slice(fileString.indexOf('\n}') + 2);
var metaDataEnd = lib.getMetadataEnd(fileString, metaDataStart + 1);
// Parse YAML metadata
} else if (fileString.indexOf('----') === 0) {
var sections = fileString.split('----');
postData = jsYAML.load(sections[1]);
if (!metaDataEnd) {
return grunt.fail.fatal(errMessage);
}
// Extract the content by removing the metadata section
postData.markdown = sections.slice(2).join('----');
} else {
grunt.fail.fatal('the metadata for the following post is formatted incorrectly: ' + postPath.red);
}
postData.date = new Date(postData.date.getUTCFullYear(), postData.date.getUTCMonth(), postData.date.getUTCDate(), postData.date.getUTCHours(), postData.date.getUTCMinutes(), postData.date.getUTCSeconds());
postData = eval('(' + fileString.substr(metaDataStart, metaDataEnd) + ')');
postData.date = new Date(postData.date);
postData.markdown = fileString.slice(metaDataEnd);
return postData;
} catch (e) {
grunt.fail.fatal('the metadata for the following post is formatted incorrectly: ' + postPath.red);
grunt.fail.fatal(errMessage);
}

@@ -191,3 +243,3 @@ };

// Check if the post was last modified when the cached version was last modifie
// Check if the post was last modified when the cached version was last modified
if (('' + fs.statSync(post.sourcePath).mtime) === ('' + new Date(post.lastModified))) {

@@ -211,3 +263,3 @@

} catch (e) {
grunt.fail.fatal('data could not be parsed from ' + options.data + '.');
grunt.fail.fatal('Data could not be parsed from ' + options.data + '.');
}

@@ -217,3 +269,3 @@ } else if (typeof options.data === 'object') {

} else {
grunt.fail.fatal('data format not recognized.');
grunt.fail.fatal('options.data format not recognized. Must be an Object or String.');
}

@@ -236,5 +288,7 @@ };

lib.setPostUrls(postCollection);
postCollection.forEach( function (post) {
postCollection.forEach(function (post) {
post.dest = lib.getDestFromUrl(post.url);
});
lib.sortPosts(postCollection);

@@ -244,2 +298,3 @@

// Remove data that will not be passed to templates for rendering
templateData.posts.forEach(function (post) {

@@ -254,3 +309,5 @@

// Record how long it takes to generate posts
var postStart = new Date().getTime();
lib.generatePosts(templateData);

@@ -262,3 +319,5 @@

// Record how long it takes to generate pages
var pageStart = new Date().getTime();
if (options.pageSrc) {

@@ -295,3 +354,3 @@ lib.generatePages(templateData);

/**
* Updates the post collection with each post's destination
* Updates the post collection with each post's url
* @param {Array} postCollection Collection of parsed posts with the content and metadata properties

@@ -306,3 +365,3 @@ */

/**
* Returns the post url based on the url property and postData
* Returns the post url based on the url property and post metadata
* @param {Object} post Post object containing all metadata properties of the post

@@ -348,3 +407,3 @@ * @return {String}

} else {
grunt.fail.fatal('required ' + urlSegment + ' attribute not found in the following post\'s metadata: ' + post.sourcePath + '.');
grunt.fail.fatal('Required ' + urlSegment + ' attribute not found in the following post\'s metadata: ' + post.sourcePath + '.');
}

@@ -357,3 +416,3 @@ });

/**
* Gets a post's or page's destionation based on its url
* Gets a post's or page's destination based on its url
* @param {String} url Url to determine the destination from

@@ -363,2 +422,4 @@ */

var dest = _this.data.dest + '/' + url;
// Ensures that a .html is present at the end of the file's destination path
if (dest.indexOf('.html') === -1) {

@@ -396,4 +457,4 @@ if (dest.lastIndexOf('/') === dest.length - 1) {

// Determine the template engine based on the file's extention name
templateEngine = templateEngines[path.extname(_this.data.layout).slice(1)];
// Determine the template engine based on the file's extension name
templateEngine = templateEngines[path.extname(_this.data.layout).slice(1).toLowerCase()];

@@ -408,2 +469,3 @@ var layoutString = fs.readFileSync(_this.data.layout, 'utf8');

grunt.log.debug(JSON.stringify(templateData, null, ' '));
grunt.file.write(post.dest, fn(templateData));

@@ -436,2 +498,3 @@ grunt.log.ok('Created '.green + 'post'.blue + ' at: ' + post.dest);

templateData.currentPage = path.basename(abspath, path.extname(abspath));
grunt.log.debug(JSON.stringify(templateData, null, ' '));
grunt.file.write(dest, fn(templateData));

@@ -473,4 +536,4 @@ grunt.log.ok('Created '.green + 'page'.magenta + ' at: ' + dest);

// If the template engine is specified, don't render templates with other filetypes
if (options.templateEngine && path.extname(abspath) !== '.' + options.templateEngine) {
// If options.templateEngine is specified, don't render templates with other file extensions
if (options.templateEngine && path.extname(abspath).toLowerCase() !== '.' + options.templateEngine) {
return false;

@@ -483,3 +546,3 @@ }

/**
* Default function to get post groups for each paginated list page by grouping a specified number of posts per page
* Default function to get post groups for each paginated page by grouping a specified number of posts per page
* @param {Array} postCollection Collection of parsed posts with the content and metadata properties

@@ -524,3 +587,3 @@ * @return {Array} Array of post arrays to be displayed on each paginated page

/**
* Creates paginated pages with a specified number of posts per page
* Creates paginated pages based on a scheme to group posts
* @param {Object} templateData Data to be passed to templates for rendering

@@ -536,3 +599,4 @@ * @param {Object} pagination Configuration object for pagination

pages.forEach(function (page, currentIndex) {
grunt.file.write(lib.getDestFromUrl(page.url), fn({
var templateRenderData = {
currentIndex: currentIndex,

@@ -544,3 +608,6 @@ pages: _.map(pages, function (page) {

data: templateData.data || {}
}));
};
grunt.log.debug(JSON.stringify(templateRenderData, null, ' '));
grunt.file.write(lib.getDestFromUrl(page.url), fn(templateRenderData));
grunt.log.ok('Created '.green + 'paginated'.rainbow + ' page'.magenta + ' at: ' + lib.getDestFromUrl(page.url));

@@ -605,3 +672,3 @@ });

/**
* Gets a list page's destination to be written
* Gets a list page's url based on its id, pagination.url, and options.pageSrc
* @param {Number} pageId Identifier of current page to be written

@@ -622,3 +689,3 @@ * @param {Object} pagination Configuration object for pagination

} else {
grunt.fail.fatal('the pagination.listPage must be within the options.pageSrc directory.');
grunt.fail.fatal('The pagination.listPage must be within the options.pageSrc directory.');
}

@@ -636,3 +703,3 @@ }

// Every other list page's url is generated using the urlFormat property and is either generated
// Every other list page's url is generated using the pagination.url property and is either generated
// relative to the folder that contains the listPage or relative to the root of the site

@@ -650,3 +717,3 @@ } else {

// Removed trailing index.html from urls
// Remove unnecessary trailing index.html from urls
if (url.lastIndexOf('index.html') === url.length - 'index.html'.length) {

@@ -653,0 +720,0 @@ url = url.slice(0, - 'index.html'.length);

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc