From d24df27c7307e842c27a0c93ea1db5c4492112a4 Mon Sep 17 00:00:00 2001 From: jondashkyle Date: Sat, 19 May 2018 18:56:24 -0700 Subject: [PATCH 01/17] move isDate to methods --- lib/file.js | 0 lib/methods.js | 7 ++++++- lib/utils.js | 6 +----- 3 files changed, 7 insertions(+), 6 deletions(-) create mode 100644 lib/file.js diff --git a/lib/file.js b/lib/file.js new file mode 100644 index 0000000..e69de29 diff --git a/lib/methods.js b/lib/methods.js index dcd14ab..d3426f2 100644 --- a/lib/methods.js +++ b/lib/methods.js @@ -1,8 +1,13 @@ module.exports = { - parseHref + parseHref, + isDate } function parseHref (str) { if (str.length > 1) return str.replace(/\/+$/, '') else return str } + +function isDate (str) { + return /^\d{4}-\d{1,2}-\d{1,2}$/.test(str) +} diff --git a/lib/utils.js b/lib/utils.js index ae70d1d..30db07c 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -213,7 +213,7 @@ function sortBy (state, value, key, order) { } // date or string - if (isDate(alpha) && isDate(beta)) { + if (methods.isDate(alpha) && methods.isDate(beta)) { return new Date(alpha) - new Date(beta) } else { return alpha.localeCompare(beta) @@ -243,7 +243,3 @@ function isPage (value) { !value.extension ) } - -function isDate (str) { - return /^\d{4}-\d{1,2}-\d{1,2}$/.test(str) -} From b413d81f57f145dd9646c02a89795e6195b274b0 Mon Sep 17 00:00:00 2001 From: jondashkyle Date: Sat, 19 May 2018 20:47:54 -0700 Subject: [PATCH 02/17] restructure and stubbing out the new file utilities --- file.js | 1 + index.js | 1 + lib/file.js | 0 lib/file/index.js | 51 +++++++++++++ lib/file/utils.js | 3 + lib/page/index.js | 51 +++++++++++++ lib/page/utils.js | 130 ++++++++++++++++++++++++++++++++++ lib/{index.js => template.js} | 75 ++++++-------------- lib/utils.js | 124 -------------------------------- package.json | 2 +- test.js | 2 +- 11 files changed, 260 insertions(+), 180 deletions(-) create mode 100644 file.js create mode 100644 index.js delete mode 100644 lib/file.js create mode 100644 lib/file/index.js create mode 100644 lib/file/utils.js create mode 100644 lib/page/index.js create mode 100644 lib/page/utils.js rename lib/{index.js => template.js} (50%) diff --git a/file.js b/file.js new file mode 100644 index 0000000..e60c77b --- /dev/null +++ b/file.js @@ -0,0 +1 @@ +module.exports = require('./lib/file') diff --git a/index.js b/index.js new file mode 100644 index 0000000..ea346c7 --- /dev/null +++ b/index.js @@ -0,0 +1 @@ +module.exports = require('./lib/page') diff --git a/lib/file.js b/lib/file.js deleted file mode 100644 index e69de29..0000000 diff --git a/lib/file/index.js b/lib/file/index.js new file mode 100644 index 0000000..dc32809 --- /dev/null +++ b/lib/file/index.js @@ -0,0 +1,51 @@ +var NanoTemplate = require('../template') +var objectKeys = require('object-keys') +var methods = require('../methods') +var utils = require('./utils') + +module.exports = wrapper + +class File extends NanoTemplate { + constructor (state, value) { + super(state, value) + var self = this + + // add utilities + objectKeys(utils).forEach(function (key) { + self[key] = function (...args) { + this._value = utils[key](this._state, this._value, ...args) + return this + } + }) + } +} + +function wrapper (state) { + return function (value) { + return new File(state, parseInitialValue(state, value)) + } +} + +function parseInitialValue (state, value) { + // defaults + state = state || { } + state.content = state.content || { } + + // grab our content + var href = state.href || '/' + var page = state.content[methods.parseHref(href)] || { } + + // set the value + switch (typeof value) { + case 'string': + // if passing a string assume we want a url + return utils.find(state, page, value) + case 'object': + // if an object and it contains value grab that value + if (typeof value.value === 'function') return value.value() + else return value + default: + // if no value, pass our page + return value || page + } +} diff --git a/lib/file/utils.js b/lib/file/utils.js new file mode 100644 index 0000000..51dbcc1 --- /dev/null +++ b/lib/file/utils.js @@ -0,0 +1,3 @@ +module.exports = { + +} \ No newline at end of file diff --git a/lib/page/index.js b/lib/page/index.js new file mode 100644 index 0000000..0c5dab4 --- /dev/null +++ b/lib/page/index.js @@ -0,0 +1,51 @@ +var NanoTemplate = require('../template') +var objectKeys = require('object-keys') +var methods = require('../methods') +var utils = require('./utils') + +module.exports = wrapper + +class Page extends NanoTemplate { + constructor (state, value) { + super(state, value) + var self = this + + // add utilities + objectKeys(utils).forEach(function (key) { + self[key] = function (...args) { + this._value = utils[key](this._state, this._value, ...args) + return this + } + }) + } +} + +function wrapper (state) { + return function (value) { + return new Page(state, parseInitialValue(state, value)) + } +} + +function parseInitialValue (state, value) { + // defaults + state = state || { } + state.content = state.content || { } + + // grab our content + var href = state.href || '/' + var page = state.content[methods.parseHref(href)] || { } + + // set the value + switch (typeof value) { + case 'string': + // if passing a string assume we want a url + return utils.find(state, page, value) + case 'object': + // if an object and it contains value grab that value + if (typeof value.value === 'function') return value.value() + else return value + default: + // if no value, pass our page + return value || page + } +} diff --git a/lib/page/utils.js b/lib/page/utils.js new file mode 100644 index 0000000..4755768 --- /dev/null +++ b/lib/page/utils.js @@ -0,0 +1,130 @@ +var objectValues = require('object-values') +var objectKeys = require('object-keys') +var resolve = require('resolve-path') +var methods = require('../methods') + +module.exports = { + children, + file, + files, + find, + hasView, + images, + pages, + sortBy +} + +function children (state, value) { + return pages(state, value) +} + +function file (state, value, key) { + try { + return value.files[key] || { } + } catch (err) { + return { } + } +} + +function files (state, value) { + try { + return value.files || { } + } catch (err) { + return { } + } +} + +function find (state, value, url) { + try { + // normalize + url = methods.parseHref(url) + + // grab from root + if (url.indexOf('/') === 0) { + return state.content[url] + } + + // if on a page grab relative + if (typeof value.url === 'string') { + return state.content[resolve(value.url, url)] + } + + // fall back to href + return state.content[resolve(state.href || '/', url)] + } catch (err) { + return { } + } +} + +function hasView (state, value) { + try { + return typeof this._value.view !== 'undefined' + } catch (err) { + return false + } +} + +function images (state, value) { + try { + return objectKeys(value.files).reduce(function (res, cur) { + if ( + typeof value.files[cur] === 'object' && + value.files[cur].type === 'image' + ) { + res[cur] = value.files[cur] + } + return res + }, { }) + } catch (err) { + return { } + } +} + +function pages (state, value) { + try { + var base = value.url.replace(/^\//, '') ? value.url : '' + var regex = new RegExp('^' + base + '/[^/]+/?$') + return objectKeys(state.content) + .filter(key => regex.test(key.trim())) + .reduce(readPage, { }) + } catch (err) { + console.log(err) + return { } + } + + function readPage (result, key) { + var page = state.content[key] + if (page) result[key] = page + return result + } +} + +function sortBy (state, value, key, order) { + try { + return objectValues(value).sort(sort) + } catch (err) { + return [ ] + } + + function sort (a, b) { + try { + var alpha = a[key] + var beta = b[key] + + // reverse order + if (order === 'desc') { + alpha = b[key] + beta = a[key] + } + + // date or string + if (methods.isDate(alpha) && methods.isDate(beta)) { + return new Date(alpha) - new Date(beta) + } else { + return alpha.localeCompare(beta) + } + } catch (err) { + return 0 + } + } +} diff --git a/lib/index.js b/lib/template.js similarity index 50% rename from lib/index.js rename to lib/template.js index 11e67af..228de80 100644 --- a/lib/index.js +++ b/lib/template.js @@ -3,10 +3,10 @@ var objectKeys = require('object-keys') var methods = require('./methods') var utils = require('./utils') -module.exports = wrapper - -class Page { +module.exports = class NanoTemplate { constructor (state, value) { + var self = this + // defaults state = state || { } state.content = state.content || { } @@ -17,16 +17,14 @@ class Page { // private data this._state = state || { } this._value = value || { } - } - url () { - try { - // file or page - if (this._value.extension) return this._value.source || '' - else return this._value.url || '' - } catch (err) { - return '' - } + // add utilities + objectKeys(utils).forEach(function (key) { + self[key] = function (...args) { + this._value = utils[key](this._state, this._value, ...args) + return this + } + }) } keys (key) { @@ -42,12 +40,11 @@ class Page { return this.values(key) } - values (key) { - var obj = (typeof key !== 'undefined') ? this._value[key] : this._value - if (typeof obj === 'object') { - return objectValues(obj) || [ ] - } else { - return obj || [ ] + url () { + try { + return this._value.url || '' + } catch (err) { + return '' } } @@ -64,43 +61,13 @@ class Page { return undefined } } -} - -// dynamically add tools -objectKeys(utils).forEach(function (key) { - Page.prototype[key] = function (...args) { - this._value = utils[key](this._state, this._value, ...args) - return this - } -}) - -function wrapper (state) { - // defaults - state = state || { } - state.content = state.content || { } - - // compose and get on with it - return function (value) { - return new Page(state, parseValue(value)) - } - function parseValue (value) { - // grab our content - var href = state.href || '/' - var page = state.content[methods.parseHref(href)] || { } - - // set the value - switch (typeof value) { - case 'string': - // if passing a string assume we want a url - return utils.find(state, page, value) - case 'object': - // if an object and it contains value grab that value - if (typeof value.value === 'function') return value.value() - else return value - default: - // if no value, pass our page - return value || page + values (key) { + var obj = (typeof key !== 'undefined') ? this._value[key] : this._value + if (typeof obj === 'object') { + return objectValues(obj) || [ ] + } else { + return obj || [ ] } } } diff --git a/lib/utils.js b/lib/utils.js index 30db07c..224b95d 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,69 +1,18 @@ var objectValues = require('object-values') var objectKeys = require('object-keys') var resolve = require('resolve-path') -var methods = require('./methods') module.exports = { - children, - file, - files, - find, first, - hasView, - images, isActive, // isFirst, // isLast, last, - pages, parent, shuffle, - sortBy, visible } -function children (state, value) { - return pages(state, value) -} - -function file (state, value, key) { - try { - return value.files[key] || { } - } catch (err) { - return { } - } -} - -function files (state, value) { - try { - return value.files || { } - } catch (err) { - return { } - } -} - -function find (state, value, url) { - try { - // normalize - url = methods.parseHref(url) - - // grab from root - if (url.indexOf('/') === 0) { - return state.content[url] - } - - // if on a page grab relative - if (typeof value.url === 'string') { - return state.content[resolve(value.url, url)] - } - - // fall back to href - return state.content[resolve(state.href || '/', url)] - } catch (err) { - return { } - } -} - function first (state, value) { try { var obj = value || { } @@ -73,31 +22,6 @@ function first (state, value) { } } -function hasView (state, value) { - try { - return typeof this._value.view !== 'undefined' - } catch (err) { - return false - } -} - -function images (state, value) { - try { - return objectKeys(value.files || { }) - .reduce(function (res, cur) { - if ( - typeof value.files[cur] === 'object' && - value.files[cur].type === 'image' - ) { - res[cur] = value.files[cur] - } - return res - }, { }) - } catch (err) { - return { } - } -} - function isActive (state, value) { try { return value.url === state.href @@ -147,24 +71,6 @@ function last (state, value) { } } -function pages (state, value) { - try { - var base = value.url.replace(/^\//, '') ? value.url : '' - var regex = new RegExp('^' + base + '/[^/]+/?$') - return objectKeys(state.content) - .filter(key => regex.test(key.trim())) - .reduce(readPage, { }) - } catch (err) { - return { } - } - - function readPage (result, key) { - var page = state.content[key] - if (page) result[key] = page - return result - } -} - function parent (state, value) { try { var url = resolve(value.url, '../') @@ -194,36 +100,6 @@ function shuffle (state, value) { } } -function sortBy (state, value, key, order) { - try { - return objectValues(value).sort(sort) - } catch (err) { - return [ ] - } - - function sort (a, b) { - try { - var alpha = a[key] - var beta = b[key] - - // reverse order - if (order === 'desc') { - alpha = b[key] - beta = a[key] - } - - // date or string - if (methods.isDate(alpha) && methods.isDate(beta)) { - return new Date(alpha) - new Date(beta) - } else { - return alpha.localeCompare(beta) - } - } catch (err) { - return 0 - } - } -} - function visible (state, value) { try { if (isPage(value)) { diff --git a/package.json b/package.json index b03a5c7..262a21e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "nanopage", "version": "0.2.0", "description": "handy utility methods for traversing content state", - "main": "lib/index.js", + "main": "index.js", "scripts": { "test": "standard --fix && node test.js" }, diff --git a/test.js b/test.js index 0a4fdb6..c7b05cc 100644 --- a/test.js +++ b/test.js @@ -1,5 +1,5 @@ var test = require('tape') -var Page = require('./lib') +var Page = require('./') var page = new Page(createState()) From b0349dbc73c265f50cb202e72f2e0245e6b31cf3 Mon Sep 17 00:00:00 2001 From: jondashkyle Date: Sat, 19 May 2018 20:59:06 -0700 Subject: [PATCH 03/17] docs --- readme.md | 140 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 78 insertions(+), 62 deletions(-) diff --git a/readme.md b/readme.md index 1294a6f..c306c78 100644 --- a/readme.md +++ b/readme.md @@ -19,14 +19,18 @@ var state = { title: 'Just a site', text: 'With some text', tags: ['and', 'some', 'tags'] + url: '/' }, '/example': { title: 'Example', text: 'Scope it out', - great: { - demo: 'Am I right?', - nah: 'Ok nbd.' - } + url: '/example' + }, + '/image.jpg': { + filename: 'image.jpg', + extension: 'jpg', + type: 'image', + url: '/content/image.jpg' } } } @@ -57,7 +61,7 @@ var lastTitle = page(last).value().title // or like this - End a query and return it’s value by calling `.value()` or `.v()` - Values can be reused in new queries by doing `page(oldQuery)` -Want to transform a directory of files and folders into flat content state? Try [Nanocontent](https://github.com/jondashkyle/nanocontent)! Super handy to use with [Enoki](https://github.com/enokidotsite/enoki) and [Choo](https://github.com/choojs/choo). If using Choo, you might [not even need it](#extra). +Want to transform a directory of files and folders into flat content state? Try [Nanocontent](https://github.com/jondashkyle/nanocontent)! Super handy to use with [Enoki](https://github.com/enokidotsite/enoki) and [Choo](https://github.com/choojs/choo) and the provided [plugin](#choo). ## Philosophy @@ -65,15 +69,40 @@ State is really handy. Especially global state. We ended up with state when weba After a while, we started using state for sites too. That is, sites that look more like sites and less like apps. Mostly because state is super handy. However, state can get really messy as sites get larger. Where do you store data? How do you reference it? If you have ten nested pages, do you have ten nested objects? -Instead of all of this complexity, lets reintroduce the URL. Each page url of your site is a key in a flat object. We can simply use the `window.location` to grab the data/content for the current page. Or, we can use any arbitrary url, like `/members/nelson`. +Instead of all of this complexity, lets reintroduce the URL. Each page url of your site is a key in a flat object. We can simply use the `window.location` to grab the data/content for the current page. Or, we can use any arbitrary url, like `/foo/bar`. This way of organizing state for sites as a flat object of page urls makes it super trivial to access content in your views and pass it down into components, or whatever. Ok cool! -## Extra +## Files + +Nanopage provides utilities for `file()` addition to the `page()`. + +```js +var File = require('nanopage/file') + +var state = { + '/': { + title: 'Index', + url: '/' + }, + '/example.jpg': { + title: 'Example', + filename: 'example.jpg', + extension: 'jpg', + url: '/content/example.jpg' + } +} + +// instantiate the file +var file = new File(state) + +// grab some metadata +var example = file('/example.jpg').value() +``` -Using Choo? Try the plugin! Don’t need all the bells and whistles? Try creating your own basic Choo plugin from scratch. +## Choo -
Use the Choo plugin +Using Choo? Try the plugin! ```js var html = require('choo/html') @@ -84,28 +113,54 @@ app.use(require('nanopage/choo')) app.route('*', function (state, emit) { return html` - ${state.page().value('title')} + +

${state.page().value('title')}

+ + ` }) if (module.parent) module.exports = app else app.mount('body') ``` -
-
Basic vanilla Choo plugin +## Global utilities -```js -app.use(function (state, emitter) { - state.page = function (key) { - key = key || (state.href || '/') - return state.content[key] - } -}) -``` -
+These utilities work for both `page()` and `file()` + +#### `.first()` + +Returns the first `page` or `file`. + +#### `.isActive()` + +Is the current page active? Returns boolean. + +#### `.last()` + +Returns the last `page` or `file`. + +#### `.parent()` + +The parent of the current page. + +#### `.toArray()` + +Converts the values of an object to an array. + +#### `.v()` + +Alias for `.value()`. + +#### `.value()` -## Methods +Return the current value. Not chainable. + +#### `.visible()` + +Returns if the current value key `visible` is not `false`. + +## Page utilities #### `.children()` @@ -123,10 +178,6 @@ Files of the current `page`. Locate a `sub-page` of the `current page` based on the `href`. -#### `.first()` - -Returns the first `page` or `file`. - #### `.hasView()` Does the current page have a custom view? @@ -135,51 +186,16 @@ Does the current page have a custom view? Images of the current page. -#### `.isActive()` - -Is the current page active? Returns boolean. - -#### `.last()` - -Returns the last `page` or `file`. - -#### `.page()` - -The current page. - #### `.pages()` Sub-pages of the current page. -#### `.parent()` - -The parent of the current page. - #### `.shuffle()` Shuffle values of an array. -#### `.sort()` - -Sorts the current value’s `.pages` by `.order`. Formatting of `.order` follows the arguments of `.sortBy` separated by a space. For example, `date asc`. - #### `.sortBy(key, order)` Sort the `files` or `pages` based by a certain key. Order can be either `asc` or `desc`. For example, `.sortBy('name', 'desc')` or `.sortBy('date', 'asc')`. -#### `.toArray()` - -Converts the values of an object to an array. - -#### `.v()` - -Alias for `.value()`. - -#### `.value()` - -Return the current value. Not chainable. - -#### `.visible()` - -Returns if the current value key `visible` is not `false`. - +## File utilities \ No newline at end of file From cc1c4f0b64d59b427b0b77330acd4ebc75573742 Mon Sep 17 00:00:00 2001 From: jondashkyle Date: Sat, 19 May 2018 21:35:17 -0700 Subject: [PATCH 04/17] adding new file and page methods --- lib/file/index.js | 3 ++- lib/file/utils.js | 7 +++++-- lib/methods.js | 22 +++++++++++++++++++++- lib/page/utils.js | 11 ++++------- lib/utils.js | 29 ++++++++++++++++++++--------- package.json | 1 + readme.md | 12 ++++++++++-- test.js | 6 ++++++ 8 files changed, 69 insertions(+), 22 deletions(-) diff --git a/lib/file/index.js b/lib/file/index.js index dc32809..70ecd09 100644 --- a/lib/file/index.js +++ b/lib/file/index.js @@ -1,4 +1,5 @@ var NanoTemplate = require('../template') +var utilsPage = require('../page/utils') var objectKeys = require('object-keys') var methods = require('../methods') var utils = require('./utils') @@ -39,7 +40,7 @@ function parseInitialValue (state, value) { switch (typeof value) { case 'string': // if passing a string assume we want a url - return utils.find(state, page, value) + return utilsPage.file(state, page, value) case 'object': // if an object and it contains value grab that value if (typeof value.value === 'function') return value.value() diff --git a/lib/file/utils.js b/lib/file/utils.js index 51dbcc1..68fd2c9 100644 --- a/lib/file/utils.js +++ b/lib/file/utils.js @@ -1,3 +1,6 @@ module.exports = { - -} \ No newline at end of file + source: noop, + sizes: noop +} + +function noop () { } diff --git a/lib/methods.js b/lib/methods.js index d3426f2..93f25ad 100644 --- a/lib/methods.js +++ b/lib/methods.js @@ -1,6 +1,10 @@ +var parsePath = require('parse-filepath') + module.exports = { parseHref, - isDate + isDate, + isPage, + hasUrl } function parseHref (str) { @@ -11,3 +15,19 @@ function parseHref (str) { function isDate (str) { return /^\d{4}-\d{1,2}-\d{1,2}$/.test(str) } + +function isPage (value) { + try { + var url = hasUrl(value) ? value.url : value + return parsePath(url).ext === '' + } catch (err) { + return false + } +} + +function hasUrl (value) { + return ( + typeof value === 'object' && + typeof value.url === 'string' + ) +} diff --git a/lib/page/utils.js b/lib/page/utils.js index 4755768..2ad56fe 100644 --- a/lib/page/utils.js +++ b/lib/page/utils.js @@ -15,15 +15,13 @@ module.exports = { } function children (state, value) { + // alias for pages return pages(state, value) } function file (state, value, key) { - try { - return value.files[key] || { } - } catch (err) { - return { } - } + // alias for find + return find(state, value, key) } function files (state, value) { @@ -88,13 +86,12 @@ function pages (state, value) { .filter(key => regex.test(key.trim())) .reduce(readPage, { }) } catch (err) { - console.log(err) return { } } function readPage (result, key) { var page = state.content[key] - if (page) result[key] = page + if (methods.isPage(page)) result[key] = page return result } } diff --git a/lib/utils.js b/lib/utils.js index 224b95d..ba57ddf 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,9 +1,12 @@ var objectValues = require('object-values') var objectKeys = require('object-keys') var resolve = require('resolve-path') +var methods = require('./methods') module.exports = { first, + isFile, + isPage, isActive, // isFirst, // isLast, @@ -30,6 +33,22 @@ function isActive (state, value) { } } +function isFile (state, value) { + try { + return (isPage(state, value) === false) + } catch (err) { + return false + } +} + +function isPage (state, value) { + try { + return methods.isPage(value) + } catch (err) { + return false + } +} + /* function isFirst (state, value) { try { @@ -102,7 +121,7 @@ function shuffle (state, value) { function visible (state, value) { try { - if (isPage(value)) { + if (methods.isPage(value)) { return value.visible !== false } else { return objectValues(value).filter(obj => obj.visible !== false) @@ -111,11 +130,3 @@ function visible (state, value) { return false } } - -function isPage (value) { - return ( - typeof value === 'object' && - typeof value.url === 'string' && - !value.extension - ) -} diff --git a/package.json b/package.json index 262a21e..a7ca45d 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "dependencies": { "object-keys": "^1.0.11", "object-values": "^2.0.0", + "parse-filepath": "^1.0.2", "resolve-path": "^1.4.0", "xtend": "^4.0.1" }, diff --git a/readme.md b/readme.md index c306c78..130631a 100644 --- a/readme.md +++ b/readme.md @@ -75,7 +75,7 @@ This way of organizing state for sites as a flat object of page urls makes it su ## Files -Nanopage provides utilities for `file()` addition to the `page()`. +Nanopage provides utilities for files via `file()` addition to `page()`. ```js var File = require('nanopage/file') @@ -134,7 +134,15 @@ Returns the first `page` or `file`. #### `.isActive()` -Is the current page active? Returns boolean. +Is the current value active? Returns boolean. + +#### `.isFile()` + +Is the current value a file? Returns boolean. + +#### `.isPage()` + +Is the current value a page? Returns boolean. #### `.last()` diff --git a/test.js b/test.js index c7b05cc..10092ad 100644 --- a/test.js +++ b/test.js @@ -86,6 +86,12 @@ function createState () { text: 'This is a test', url: '/example' }, + '/image.jpg': { + filename: 'image.jpg', + extension: 'jpg', + type: 'image', + url: '/content/image.jpg' + }, '/example/child': { title: 'Child', date: '2018-04-01', From d2aece0954b3fbc73ff036fe69a9857e146bc07a Mon Sep 17 00:00:00 2001 From: jondashkyle Date: Sat, 19 May 2018 21:40:36 -0700 Subject: [PATCH 05/17] file testing --- lib/page/utils.js | 12 +++++++++++- test.js | 10 +++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/lib/page/utils.js b/lib/page/utils.js index 2ad56fe..2296514 100644 --- a/lib/page/utils.js +++ b/lib/page/utils.js @@ -26,10 +26,20 @@ function file (state, value, key) { function files (state, value) { try { - return value.files || { } + var base = value.url.replace(/^\//, '') ? value.url : '' + var regex = new RegExp('^' + base + '/[^/]+/?$') + return objectKeys(state.content) + .filter(key => regex.test(key.trim())) + .reduce(readFile, { }) } catch (err) { return { } } + + function readFile (result, key) { + var file = state.content[key] + if (methods.isFile(file)) result[key] = file + return result + } } function find (state, value, url) { diff --git a/test.js b/test.js index 10092ad..182b6d0 100644 --- a/test.js +++ b/test.js @@ -1,7 +1,9 @@ var test = require('tape') -var Page = require('./') +var Page = require('./lib/page') +var File = require('./lib/file') var page = new Page(createState()) +var file = new File(createState()) test('output', function (t) { t.ok(typeof page === 'function', 'outputs function') @@ -63,6 +65,12 @@ test('parent', function (t) { t.end() }) +test('file', function (t) { + t.ok(typeof file('/image.jpg').value() === 'object', 'value is type object') + t.ok(file('/image.jpg').value('url') === '/content/image.jpg', 'url exists') + t.end() +}) + function createState () { return { href: '/', From 850bb8cd44cbaa601d992a1013d3170780ee25c9 Mon Sep 17 00:00:00 2001 From: jondashkyle Date: Sat, 19 May 2018 21:41:40 -0700 Subject: [PATCH 06/17] add source utility --- lib/template.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/template.js b/lib/template.js index 228de80..adc9da0 100644 --- a/lib/template.js +++ b/lib/template.js @@ -36,6 +36,10 @@ module.exports = class NanoTemplate { } } + source () { + return this.value('source') + } + toArray (key) { return this.values(key) } From 76cb36d10508cede5fa2eafe31f4bb6439bfd3d6 Mon Sep 17 00:00:00 2001 From: jondashkyle Date: Sat, 19 May 2018 22:07:00 -0700 Subject: [PATCH 07/17] files and stuff --- lib/methods.js | 5 +++++ lib/page/utils.js | 11 +++-------- lib/utils.js | 20 ++++++++++++++------ readme.md | 12 ++++++------ test.js | 10 +++++++++- 5 files changed, 37 insertions(+), 21 deletions(-) diff --git a/lib/methods.js b/lib/methods.js index 93f25ad..feaa0ef 100644 --- a/lib/methods.js +++ b/lib/methods.js @@ -3,6 +3,7 @@ var parsePath = require('parse-filepath') module.exports = { parseHref, isDate, + isFile, isPage, hasUrl } @@ -16,6 +17,10 @@ function isDate (str) { return /^\d{4}-\d{1,2}-\d{1,2}$/.test(str) } +function isFile (value) { + return isPage(value) === false +} + function isPage (value) { try { var url = hasUrl(value) ? value.url : value diff --git a/lib/page/utils.js b/lib/page/utils.js index 2296514..116859d 100644 --- a/lib/page/utils.js +++ b/lib/page/utils.js @@ -20,7 +20,6 @@ function children (state, value) { } function file (state, value, key) { - // alias for find return find(state, value, key) } @@ -74,13 +73,9 @@ function hasView (state, value) { function images (state, value) { try { - return objectKeys(value.files).reduce(function (res, cur) { - if ( - typeof value.files[cur] === 'object' && - value.files[cur].type === 'image' - ) { - res[cur] = value.files[cur] - } + var _files = files(state, value) + return objectKeys(_files).reduce(function (res, key) { + if (_files[key].type === 'image') res[key] = _files[key] return res }, { }) } catch (err) { diff --git a/lib/utils.js b/lib/utils.js index ba57ddf..b609858 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -18,8 +18,12 @@ module.exports = { function first (state, value) { try { - var obj = value || { } - return obj[objectKeys(obj)[0]] || { } + if (typeof value === 'object') { + var obj = value || { } + return obj[objectKeys(obj)[0]] || { } + } else { + return value[0] + } } catch (err) { return { } } @@ -35,7 +39,7 @@ function isActive (state, value) { function isFile (state, value) { try { - return (isPage(state, value) === false) + return methods.isFile(value) } catch (err) { return false } @@ -82,9 +86,13 @@ function isLast (state, value) { function last (state, value) { try { - var obj = value || { } - var keys = objectKeys(obj) - return obj[keys[keys.length - 1]] || { } + if (typeof value === 'object') { + var obj = value || { } + var keys = objectKeys(obj) + return obj[keys[keys.length - 1]] || { } + } else { + return value[value.length - 1] + } } catch (err) { return { } } diff --git a/readme.md b/readme.md index 130631a..d78c2d4 100644 --- a/readme.md +++ b/readme.md @@ -176,15 +176,15 @@ Alias for `.pages()`. #### `.file(filename)` -Grab an individual file. For example, `.file('example.jpg')`. +Locate a child file of the current page based on the `url`. #### `.files()` -Files of the current `page`. +Child files of the current `page`. -#### `.find(href)` +#### `.find(url)` -Locate a `sub-page` of the `current page` based on the `href`. +Locate a child page of the current page based on the `url`. #### `.hasView()` @@ -192,11 +192,11 @@ Does the current page have a custom view? #### `.images()` -Images of the current page. +Child images of the current page. #### `.pages()` -Sub-pages of the current page. +Child pages of the current page. #### `.shuffle()` diff --git a/test.js b/test.js index 182b6d0..9a92583 100644 --- a/test.js +++ b/test.js @@ -68,6 +68,8 @@ test('parent', function (t) { test('file', function (t) { t.ok(typeof file('/image.jpg').value() === 'object', 'value is type object') t.ok(file('/image.jpg').value('url') === '/content/image.jpg', 'url exists') + t.ok(typeof file('/example/child/image.png').value() === 'object', 'deep value is type object') + t.ok(typeof page('/example/child').file('image.png').value() === 'object', 'page file value is type object') t.end() }) @@ -96,7 +98,7 @@ function createState () { }, '/image.jpg': { filename: 'image.jpg', - extension: 'jpg', + extension: '.jpg', type: 'image', url: '/content/image.jpg' }, @@ -105,6 +107,12 @@ function createState () { date: '2018-04-01', text: 'Look ma I’m nested', url: '/example/child' + }, + '/example/child/image.png': { + filename: 'image.png', + extension: '.png', + type: 'image', + url: '/content/example/child/image.png' } } } From e8c8dd75580f72ab537e08c62077e37419090e11 Mon Sep 17 00:00:00 2001 From: jondashkyle Date: Sun, 20 May 2018 22:17:35 -0700 Subject: [PATCH 08/17] choo plugin fixes --- choo.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/choo.js b/choo.js index 752b773..8785a87 100644 --- a/choo.js +++ b/choo.js @@ -1,8 +1,10 @@ -var Page = require('./lib') +var File = require('./lib/file') +var Page = require('./lib/page') module.exports = plugin function plugin (state, emit) { state.content = state.content || { } + state.file = new File(state) state.page = new Page(state) } From fadc8b8e70490b632002124c6a90512950e5575b Mon Sep 17 00:00:00 2001 From: jondashkyle Date: Sun, 20 May 2018 22:17:39 -0700 Subject: [PATCH 09/17] docs --- package.json | 2 +- readme.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index a7ca45d..2cf7e6d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nanopage", - "version": "0.2.0", + "version": "0.2.0-next1", "description": "handy utility methods for traversing content state", "main": "index.js", "scripts": { diff --git a/readme.md b/readme.md index d78c2d4..c3b6041 100644 --- a/readme.md +++ b/readme.md @@ -154,7 +154,7 @@ The parent of the current page. #### `.toArray()` -Converts the values of an object to an array. +Converts the values of an object to an array. Not chainable. #### `.v()` @@ -174,13 +174,13 @@ Returns if the current value key `visible` is not `false`. Alias for `.pages()`. -#### `.file(filename)` +#### `.file(url)` Locate a child file of the current page based on the `url`. #### `.files()` -Child files of the current `page`. +Child files of the current page. #### `.find(url)` From 6f69d760646b67c689c1e54aaa93be9f4b349307 Mon Sep 17 00:00:00 2001 From: jondashkyle Date: Mon, 21 May 2018 11:40:10 -0700 Subject: [PATCH 10/17] yaml to yml --- travis.yaml => travis.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename travis.yaml => travis.yml (100%) diff --git a/travis.yaml b/travis.yml similarity index 100% rename from travis.yaml rename to travis.yml From e71034ea8358d172aa36ac63288983b0d90335de Mon Sep 17 00:00:00 2001 From: jondashkyle Date: Mon, 21 May 2018 11:44:01 -0700 Subject: [PATCH 11/17] wow i cant get this right --- travis.yml => .travis.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename travis.yml => .travis.yml (100%) diff --git a/travis.yml b/.travis.yml similarity index 100% rename from travis.yml rename to .travis.yml From 23ff9621de5658ffcb81f630a8b5416e921ee9c2 Mon Sep 17 00:00:00 2001 From: jondashkyle Date: Mon, 21 May 2018 11:48:14 -0700 Subject: [PATCH 12/17] updated testing --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2cf7e6d..df09497 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "handy utility methods for traversing content state", "main": "index.js", "scripts": { - "test": "standard --fix && node test.js" + "test": "standard; node test.js" }, "repository": { "type": "git", From 2e677eb8aaf84fc2bda784edf35c51256e068b7b Mon Sep 17 00:00:00 2001 From: jondashkyle Date: Mon, 21 May 2018 12:52:34 -0700 Subject: [PATCH 13/17] file size util --- lib/file/utils.js | 12 ++++++++++-- lib/page/utils.js | 2 +- test.js | 7 ++++++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/file/utils.js b/lib/file/utils.js index 68fd2c9..6012e98 100644 --- a/lib/file/utils.js +++ b/lib/file/utils.js @@ -1,6 +1,14 @@ module.exports = { - source: noop, - sizes: noop + size, + source: noop +} + +function size (state, value, size) { + try { + return value.sizes[size.toString()] + } catch (err) { + return '' + } } function noop () { } diff --git a/lib/page/utils.js b/lib/page/utils.js index 116859d..e609edf 100644 --- a/lib/page/utils.js +++ b/lib/page/utils.js @@ -65,7 +65,7 @@ function find (state, value, url) { function hasView (state, value) { try { - return typeof this._value.view !== 'undefined' + return typeof value.view !== 'undefined' } catch (err) { return false } diff --git a/test.js b/test.js index 9a92583..3dbce3e 100644 --- a/test.js +++ b/test.js @@ -70,6 +70,7 @@ test('file', function (t) { t.ok(file('/image.jpg').value('url') === '/content/image.jpg', 'url exists') t.ok(typeof file('/example/child/image.png').value() === 'object', 'deep value is type object') t.ok(typeof page('/example/child').file('image.png').value() === 'object', 'page file value is type object') + t.ok(file('/image.jpg').size('500').v() === 'content/image-s500.jpg', 'file size') t.end() }) @@ -100,7 +101,11 @@ function createState () { filename: 'image.jpg', extension: '.jpg', type: 'image', - url: '/content/image.jpg' + url: '/content/image.jpg', + sizes: { + '100': 'content/image-s100.jpg', + '500': 'content/image-s500.jpg' + } }, '/example/child': { title: 'Child', From 7b5e04d23eaf34a3b964ed1fe91da7f319b71e4f Mon Sep 17 00:00:00 2001 From: jondashkyle Date: Wed, 23 May 2018 18:45:10 -0700 Subject: [PATCH 14/17] add globs to page and file constructors --- lib/file/index.js | 16 ++++++++++++++-- lib/page/index.js | 17 +++++++++++++++-- package.json | 3 +++ test.js | 6 ++++++ 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/lib/file/index.js b/lib/file/index.js index 70ecd09..dbe86fd 100644 --- a/lib/file/index.js +++ b/lib/file/index.js @@ -4,6 +4,9 @@ var objectKeys = require('object-keys') var methods = require('../methods') var utils = require('./utils') +var minimatch = require('minimatch') +var isGlob = require('is-glob') + module.exports = wrapper class File extends NanoTemplate { @@ -39,8 +42,8 @@ function parseInitialValue (state, value) { // set the value switch (typeof value) { case 'string': - // if passing a string assume we want a url - return utilsPage.file(state, page, value) + if (isGlob(value)) return getContentGlob(state, page, value) + else return utilsPage.file(state, page, value) case 'object': // if an object and it contains value grab that value if (typeof value.value === 'function') return value.value() @@ -50,3 +53,12 @@ function parseInitialValue (state, value) { return value || page } } + +function getContentGlob (state, page, value) { + return objectKeys(state.content) + .filter(minimatch.filter(value, { matchBase: true })) + .reduce(function (res, cur) { + res[cur] = state.content[cur] + return res + }, { }) +} diff --git a/lib/page/index.js b/lib/page/index.js index 0c5dab4..4312d23 100644 --- a/lib/page/index.js +++ b/lib/page/index.js @@ -1,8 +1,12 @@ var NanoTemplate = require('../template') +var utilsPage = require('../page/utils') var objectKeys = require('object-keys') var methods = require('../methods') var utils = require('./utils') +var minimatch = require('minimatch') +var isGlob = require('is-glob') + module.exports = wrapper class Page extends NanoTemplate { @@ -38,8 +42,8 @@ function parseInitialValue (state, value) { // set the value switch (typeof value) { case 'string': - // if passing a string assume we want a url - return utils.find(state, page, value) + if (isGlob(value)) return getContentGlob(state, page, value) + else return utilsPage.file(state, page, value) case 'object': // if an object and it contains value grab that value if (typeof value.value === 'function') return value.value() @@ -49,3 +53,12 @@ function parseInitialValue (state, value) { return value || page } } + +function getContentGlob (state, page, value) { + return objectKeys(state.content) + .filter(minimatch.filter(value, { matchBase: true })) + .reduce(function (res, cur) { + res[cur] = state.content[cur] + return res + }, { }) +} diff --git a/package.json b/package.json index df09497..3eacfbb 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,9 @@ }, "homepage": "https://github.com/jondashkyle/nanopage#readme", "dependencies": { + "glob-to-regexp": "^0.4.0", + "is-glob": "^4.0.0", + "minimatch": "^3.0.4", "object-keys": "^1.0.11", "object-values": "^2.0.0", "parse-filepath": "^1.0.2", diff --git a/test.js b/test.js index 3dbce3e..7b6f9b9 100644 --- a/test.js +++ b/test.js @@ -10,6 +10,12 @@ test('output', function (t) { t.end() }) +test('page', function (t) { + t.ok(page('/example').value('title') === 'Example', 'select page by id') + t.ok(page('/example/*').keys()[0] === '/example/child', 'select page(s) by glob') + t.end() +}) + test('value', function (t) { t.ok(typeof page().value() === 'object', 'value is a type object') t.ok(typeof page().v() === 'object', 'v alias for value') From 0047bb85a283817f960af9f7111c08f65520be6e Mon Sep 17 00:00:00 2001 From: jondashkyle Date: Wed, 23 May 2018 19:38:41 -0700 Subject: [PATCH 15/17] docs --- readme.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/readme.md b/readme.md index c3b6041..40169ef 100644 --- a/readme.md +++ b/readme.md @@ -100,6 +100,15 @@ var file = new File(state) var example = file('/example.jpg').value() ``` +## Globs + +Both the `page()` and `file()` methods accept a [glob](https://github.com/isaacs/minimatch) instead of a path. + +```js +var images = page('../*.jpg').toArray() +``` + + ## Choo Using Choo? Try the plugin! From e285d7901c8405d22b42c0b7616b64fc7c17514b Mon Sep 17 00:00:00 2001 From: jondashkyle Date: Wed, 23 May 2018 20:20:34 -0700 Subject: [PATCH 16/17] relative urls --- lib/file/index.js | 3 ++- lib/page/index.js | 3 ++- package.json | 2 +- readme.md | 6 ++++-- test.js | 4 ++++ 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/lib/file/index.js b/lib/file/index.js index dbe86fd..8727e5d 100644 --- a/lib/file/index.js +++ b/lib/file/index.js @@ -1,6 +1,7 @@ var NanoTemplate = require('../template') var utilsPage = require('../page/utils') var objectKeys = require('object-keys') +var joinPath = require('join-path') var methods = require('../methods') var utils = require('./utils') @@ -43,7 +44,7 @@ function parseInitialValue (state, value) { switch (typeof value) { case 'string': if (isGlob(value)) return getContentGlob(state, page, value) - else return utilsPage.file(state, page, value) + else return utilsPage.file(state, page, methods.parseHref(joinPath(href, value))) case 'object': // if an object and it contains value grab that value if (typeof value.value === 'function') return value.value() diff --git a/lib/page/index.js b/lib/page/index.js index 4312d23..222936f 100644 --- a/lib/page/index.js +++ b/lib/page/index.js @@ -1,6 +1,7 @@ var NanoTemplate = require('../template') var utilsPage = require('../page/utils') var objectKeys = require('object-keys') +var joinPath = require('join-path') var methods = require('../methods') var utils = require('./utils') @@ -43,7 +44,7 @@ function parseInitialValue (state, value) { switch (typeof value) { case 'string': if (isGlob(value)) return getContentGlob(state, page, value) - else return utilsPage.file(state, page, value) + else return utilsPage.file(state, page, methods.parseHref(joinPath(href, value))) case 'object': // if an object and it contains value grab that value if (typeof value.value === 'function') return value.value() diff --git a/package.json b/package.json index 3eacfbb..c464384 100644 --- a/package.json +++ b/package.json @@ -20,8 +20,8 @@ }, "homepage": "https://github.com/jondashkyle/nanopage#readme", "dependencies": { - "glob-to-regexp": "^0.4.0", "is-glob": "^4.0.0", + "join-path": "^1.1.1", "minimatch": "^3.0.4", "object-keys": "^1.0.11", "object-values": "^2.0.0", diff --git a/readme.md b/readme.md index 40169ef..77e11c5 100644 --- a/readme.md +++ b/readme.md @@ -102,10 +102,12 @@ var example = file('/example.jpg').value() ## Globs -Both the `page()` and `file()` methods accept a [glob](https://github.com/isaacs/minimatch) instead of a path. +Both the `page()` and `file()` methods also accept [globs](https://github.com/isaacs/minimatch) and relative urls to easily traverse directories and files. ```js -var images = page('../*.jpg').toArray() +var imagesParent = page('../*.jpg').toArray() +var imagesAll = page('*.jpg').toArray() +var parentTitle = page('../').value('title') ``` diff --git a/test.js b/test.js index 7b6f9b9..399ad1e 100644 --- a/test.js +++ b/test.js @@ -11,8 +11,12 @@ test('output', function (t) { }) test('page', function (t) { + var parentPage = new Page(createState()) + parentPage.href = '/example' + t.ok(page('/example').value('title') === 'Example', 'select page by id') t.ok(page('/example/*').keys()[0] === '/example/child', 'select page(s) by glob') + t.ok(page('../').value('title') === 'Index', 'select page by relative path') t.end() }) From 95243926698ed68eef886160a2fee64f760631a0 Mon Sep 17 00:00:00 2001 From: jondashkyle Date: Wed, 23 May 2018 20:20:48 -0700 Subject: [PATCH 17/17] v bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c464384..232dfc3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nanopage", - "version": "0.2.0-next1", + "version": "0.2.0-next2", "description": "handy utility methods for traversing content state", "main": "index.js", "scripts": {