Skip to content

Commit

Permalink
Merge pull request #1 from carrot/implement-view-helper
Browse files Browse the repository at this point in the history
Implement view helper
  • Loading branch information
Josh Rowley committed Jul 30, 2014
2 parents ddfbc2e + 742b06f commit 8a2dab9
Show file tree
Hide file tree
Showing 22 changed files with 304 additions and 53 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.DS_Store
node_modules
coverage
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
language: node_js
node_js:
- "0.10"
after_script:
- npm run coveralls
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@ publish:
make build
npm publish .
make unbuild

coveralls:
NODE_ENV=test istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage
108 changes: 79 additions & 29 deletions lib/index.coffee
Original file line number Diff line number Diff line change
@@ -1,42 +1,92 @@
RootsUtil = require 'roots-util'
path = require 'path'
_ = require 'lodash'
W = require 'when'
S = require 'string'
contentful = require 'contentful'
pluralize = require 'pluralize'

# This is meant to serve as an example...
errors =
no_token: 'Missing required options for roots-contentful. Please ensure
`access_token` and `space_id` are present.'
no_type_id: 'One or more of your content types is missing an `id` value'
sys_conflict:'One of your content types has `sys` as a field. This is reserved
for storing Contentful system metadata, please rename this field to a
different value.'

# Full Roots Extension API documentation located:
# http://roots.readthedocs.org/en/latest/extensions.html
module.exports = (opts) ->
# throw error if missing required config
if not (opts.access_token && opts.space_id)
throw new Error errors.no_token

module.exports = ->
class RootsContentful
# setup contentful api client
client = contentful.createClient
accessToken: opts.access_token
space: opts.space_id

class RootsContentful
constructor: (@roots) ->
# console.log @roots
@roots.config.locals ||= {}

setup: ->
configure_content(opts.content_types)
.then(get_all_content)
.then (res) =>
@roots.config.locals.contentful = res

###*
* Configures content types set in app.coffee. Sets default values if
* optional config options are missing.
* @param {Array} types - content_types set in app.coffee extension config
* @return {Promise} - returns an array of configured content types
###

configure_content = (types) ->
W.map types, (t) ->
if not t.id then return W.reject(errors.no_type_id)
if t.name then return W.resolve(t)
t.filters ?= {}
W client.contentType(t.id).then (res) ->
t.name = pluralize(S(res.name).toLowerCase().underscore().s)
return t

fs: ->
# category: 'foo'
# extract: true
# detect: (f) =>
# path.extname(f.relative) == 'js'
###*
* Fetches data from Contentful API, formats the raw data, and constructs
* the locals object
* @param {Array} types - configured content_type objects
* @return {Promise} - returns formatted locals object with all content
###

compile_hooks: ->
# category: 'foo'
get_all_content = (types) ->
W.reduce types, (m, t) ->
fetch_content(t)
.then(format_content)
.then((c) -> m[t.name] = c)
.yield(m)
, {}

# before_file: (ctx) =>
# ctx.content = ctx.content.toUpperCase()
###*
* Fetch entries for a single content type object
* @param {Object} type - content type object
* @return {Promise} - returns response from Contentful API
###

# after_file: (ctx) =>
# ctx.content = ctx.content.toUpperCase()
fetch_content = (type) ->
W client.entries(_.merge(type.filters, content_type: type.id))

# before_pass: (ctx) =>
# ctx.content = ctx.content.toUpperCase()
###*
* Formats raw response from Contentful
* @param {Object} content - entries API response for a content type
* @return {Promise} - returns formatted content type entries object
###

# after_pass: (ctx) =>
# ctx.content = ctx.content.toUpperCase()
format_content = (content) ->
W.map(content, format_entry)

# write: ->
# false
###*
* Formats a single entry object from Contentful API response
* @param {Object} e - single entry object from API response
* @return {Promise} - returns formatted entry object
###

category_hooks: ->
# after: (ctx) =>
# output = path.join(ctx.roots.config.output_path(), 'build.js')
# nodefn.call(fs.writeFile, output, @contents)
format_entry = (e) ->
if _.has(e.fields, 'sys') then return W.reject(errors.sys_conflict)
_.assign(_.omit(e, 'fields'), e.fields)
23 changes: 16 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,30 @@
"test": "test"
},
"dependencies": {
"lodash": "2.x",
"minimatch": "0.2.x",
"roots-util": "0.0.4"
"lodash": "~2.4.1",
"roots-util": "~0.0.5",
"contentful": "~0.1.2",
"when": "~3.4.2",
"string": "~1.9.0",
"pluralize": "0.0.10"
},
"devDependencies": {
"chai": "1.x",
"chai-as-promised": "4.x",
"coffee-script": "1.7.x",
"mocha": "*",
"should": "*",
"roots": "3.x"
"coveralls": "2.x",
"istanbul": "0.3.x",
"mocha": "1.x",
"roots": "3.x",
"mockery": "~1.4.0"
},
"peerDependencies": {
"roots": "3.x"
},
"scripts": {
"test": "mocha"
"test": "mocha",
"coverage": "make build; NODE_ENV=test istanbul cover ./node_modules/mocha/bin/_mocha; make unbuild; open coverage/lcov-report/index.html;",
"coveralls": "make build; make coveralls; make unbuild;"
},
"repository": {
"type": "git",
Expand Down
8 changes: 4 additions & 4 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Roots Contentful
================

[![npm](https://badge.fury.io/js/roots-contentful.png)](http://badge.fury.io/js/roots-contentful) [![tests](https://travis-ci.org/carrot/roots-contentful.png?branch=master)](https://travis-ci.org/carrot/roots-contentful) [![dependencies](https://david-dm.org/carrot/roots-contentful.png?theme=shields.io)](https://david-dm.org/carrot/roots-contentful)
[![npm](https://badge.fury.io/js/roots-contentful.png)](http://badge.fury.io/js/roots-contentful) [![tests](https://travis-ci.org/carrot/roots-contentful.png?branch=master)](https://travis-ci.org/carrot/roots-contentful) [![dependencies](https://david-dm.org/carrot/roots-contentful.png?theme=shields.io)](https://david-dm.org/carrot/roots-contentful) [![Coverage Status](https://img.shields.io/coveralls/carrot/roots-contentful.svg)](https://coveralls.io/r/carrot/roots-contentful?branch=implement-view-helper)

An extension for using roots with the Contentful CMS API.

Expand Down Expand Up @@ -34,7 +34,7 @@ module.exports =
id: 'xxxxxx',
name: 'posts',
template: 'views/_post.jade',
filter: {
filters: {
'fields.environment[in]': ['staging', 'production']
},
path: (e) -> "blogging/#{e.category}/#{slugify(e.title)}"
Expand Down Expand Up @@ -125,13 +125,13 @@ Required. The Content Type's ID on Contentful.

#### name

Optional. This is the name of the key the entries will be attached to on the `contentful` object in your views. Defaults to a [pluralized](https://github.com/blakeembrey/pluralize), [camelized](http://stringjs.com/#methods/camelize) representation of the Content Type name (e.g. 'Blog Post' => `contentful.blogPosts`)
Optional. This is the name of the key the entries will be attached to on the `contentful` object in your views. Defaults to a [pluralized](https://github.com/blakeembrey/pluralize), [underscored](http://stringjs.com/#methods/underscore) representation of the Content Type name (e.g. 'Blog Post' => `contentful.blogPosts`)

#### template

Optional. Path relative to the roots project of a template for a single entry view. Each entry in the Content Type will be passed into the template in an `entry` variable. If not given, the Content Type will not be compiled into single entry views and will only be attached to the `contentful` view helper object.

#### filter
#### filters

Optional. Takes an object with different filter criteria, see examples of how to structure the object in [Contentful's docs](https://www.contentful.com/developers/documentation/content-delivery-api/javascript/#search-filter).

Expand Down
1 change: 1 addition & 0 deletions test/fixtures/basic/about.jade
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
h1 wow
17 changes: 15 additions & 2 deletions test/fixtures/basic/app.coffee
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
roots_contentful = require '../../..'
contentful = require '../../..'

module.exports =
ignores: ["**/_*", "**/.DS_Store"]
extensions: [new roots_contentful]
extensions: [
contentful(
access_token: 'YOUR_ACCESS_TOKEN'
space_id: 'aqzq2qya2jm4'
content_types: [
{
id: '6BYT1gNiIEyIw8Og8aQAO6'
}
{
id: '7CDlVsacqQc88cmIEGYWMa'
}
]
)
]
6 changes: 5 additions & 1 deletion test/fixtures/basic/index.jade
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
p hello world
ul
- for p in contentful.blog_posts
li
h1= p.title
p= p.body
1 change: 1 addition & 0 deletions test/fixtures/custom_name/about.jade
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
h1 wow
19 changes: 19 additions & 0 deletions test/fixtures/custom_name/app.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
contentful = require '../../..'

module.exports =
ignores: ["**/_*", "**/.DS_Store"]
extensions: [
contentful(
access_token: 'YOUR_ACCESS_TOKEN'
space_id: 'aqzq2qya2jm4'
content_types: [
{
id: '6BYT1gNiIEyIw8Og8aQAO6'
name: 'press_links'
},
{
id: '7CDlVsacqQc88cmIEGYWMa'
}
]
)
]
5 changes: 5 additions & 0 deletions test/fixtures/custom_name/index.jade
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ul
- for p in contentful.press_links
li
h1= p.title
p= p.body
6 changes: 6 additions & 0 deletions test/fixtures/custom_name/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "test",
"dependencies": {
"jade": "*"
}
}
18 changes: 18 additions & 0 deletions test/fixtures/missing_config/app.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
contentful = require '../../..'

module.exports =
ignores: ["**/_*", "**/.DS_Store"]
extensions: [
contentful(
access_token: 'YOUR_ACCESS_TOKEN'
space_id: 'aqzq2qya2jm4'
content_types: [
{
name: 'test'
}
{
id: '7CDlVsacqQc88cmIEGYWMa'
}
]
)
]
5 changes: 5 additions & 0 deletions test/fixtures/missing_config/index.jade
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ul
- for p in contentful.blog_posts
li
h1= p.title
p= p.body
6 changes: 6 additions & 0 deletions test/fixtures/missing_config/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "test",
"dependencies": {
"jade": "*"
}
}
16 changes: 16 additions & 0 deletions test/fixtures/missing_token/app.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
contentful = require '../../..'

module.exports =
ignores: ["**/_*", "**/.DS_Store"]
extensions: [
contentful(
content_types: [
{
name: 'test'
}
{
id: '7CDlVsacqQc88cmIEGYWMa'
}
]
)
]
1 change: 1 addition & 0 deletions test/fixtures/missing_token/index.jade
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
h1 wow
6 changes: 6 additions & 0 deletions test/fixtures/missing_token/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "test",
"dependencies": {
"jade": "*"
}
}
1 change: 1 addition & 0 deletions test/mocha.opts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
--reporter spec
--compilers coffee:coffee-script/register
--require test/support/helpers
--timeout 30000
17 changes: 17 additions & 0 deletions test/support/helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
var chai = require('chai'),
chai_promise = require('chai-as-promised'),
mockery = require('mockery'),
path = require('path'),
_path = path.join(__dirname, '../fixtures'),
RootsUtil = require('roots-util'),
h = new RootsUtil.Helpers({ base: _path }),
roots_contentful = require('../../lib');

var should = chai.should();
chai.use(chai_promise);

global.should = should;
global.mockery = mockery;
global._path = _path;
global.h = h;
global.roots_contentful = roots_contentful;
Loading

0 comments on commit 8a2dab9

Please sign in to comment.