Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract the resolving of a page's path and test it #232

Merged
merged 3 commits into from
Apr 9, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions lib/utils/build-page/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import path from 'path'
import objectAssign from 'object-assign'
import pathResolver from './path-resolver'
import loadFrontmatter from './load-frontmatter'

export default function buildPage (directory, page) {
const pageData = loadFrontmatter(page)

const relativePath = path.relative(path.join(directory, 'pages'), page)
const pathData = pathResolver(relativePath)

return objectAssign({}, pageData, pathData)
}
27 changes: 27 additions & 0 deletions lib/utils/build-page/load-frontmatter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import fs from 'fs'
import path from 'path'
import frontMatter from 'front-matter'
import objectAssign from 'object-assign'
import htmlFrontMatter from 'html-frontmatter'

export default function loadFrontmatter (pagePath) {
const ext = path.extname(pagePath).slice(1)

// Load data for each file type.
// TODO use webpack-require to ensure data loaded
// here (in node context) is consistent with what's loaded
// in the browser.

let data
if (ext === 'md') {
const rawData = frontMatter(fs.readFileSync(pagePath, 'utf-8'))
data = objectAssign({}, rawData.attributes)
} else if (ext === 'html') {
const html = fs.readFileSync(pagePath, 'utf-8')
data = objectAssign({}, htmlFrontMatter(html), { body: html })
} else {
data = {}
}

return data
}
28 changes: 28 additions & 0 deletions lib/utils/build-page/path-resolver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import slash from 'slash'
import parsePath from 'parse-filepath'
import urlResolver from './url-resolver'

export default function pathResolver (relativePath) {
const data = {}

data.file = parsePath(relativePath)

// Remove the . from extname (.md -> md)
data.file.ext = data.file.extname.slice(1)
// Make sure slashes on parsed.dirname are correct for Windows
data.file.dirname = slash(data.file.dirname)

// Determine require path
data.requirePath = slash(relativePath)

// set the URL path (should this be renamed)
// and now looking at it, it only needs a reference to pageData
data.path = urlResolver(data, data.file)

// Set the "template path"
if (data.file.name === '_template') {
data.templatePath = `/${data.file.dirname}/`
}

return data
}
53 changes: 53 additions & 0 deletions lib/utils/build-page/url-resolver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { posix as path } from 'path'
import { startsWith } from 'lodash'

let rewritePath
try {
const gatsbyNodeConfig = path.resolve(process.cwd(), './gatsby-node.js')
const nodeConfig = require(gatsbyNodeConfig)
rewritePath = nodeConfig.rewritePath
} catch (e) {
// Ignore
}

export default function pathResolver (pageData, parsedPath) {
/**
* Determines if a hardcoded path was given in the frontmatter of a page.
*/
function hardcodedPath () {
return pageData.path
}

/**
* Determines if the path should be rewritten using rules provided by the
* user in the gatsby-node.js config file in the root of the project.
*/
function rewrittenPath () {
if (rewritePath) {
return rewritePath(parsedPath, pageData)
} else { return undefined }
}

/**
* Determines the path of the page using the default of its location on the
* filesystem.
*/
function defaultPath () {
const { dirname } = parsedPath
let { name } = parsedPath
if (name === 'template' || name === 'index') {
name = ''
}
return path.join('/', dirname, name, '/')
}

/**
* Returns a path for a page. If the page name starts with an underscore,
* undefined is returned as it does not become a page.
*/
if (!startsWith(parsedPath.name, '_')) {
return hardcodedPath() || rewrittenPath() || defaultPath()
} else {
return undefined
}
}
85 changes: 2 additions & 83 deletions lib/utils/glob-pages.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,6 @@
import glob from 'glob'
import path from 'path'
import parsePath from 'parse-filepath'
import slash from 'slash'
import fs from 'fs'
import frontMatter from 'front-matter'
import htmlFrontMatter from 'html-frontmatter'
import objectAssign from 'object-assign'
import buildPage from './build-page'
const debug = require('debug')('gatsby:glob')
let rewritePath
try {
const gatsbyNodeConfig = path.resolve(process.cwd(), './gatsby-node.js')
const nodeConfig = require(gatsbyNodeConfig)
rewritePath = nodeConfig.rewritePath
} catch (e) {
// Ignore
}

module.exports = (directory, callback) => {
const pagesData = []
Expand All @@ -39,74 +25,7 @@ module.exports = (directory, callback) => {
if (err) { return callback(err) }

pages.forEach((page) => {
const pageData = {}
pageData.file = {}

pageData.file = parsePath(path.relative(`${directory}/pages`, page))
const parsed = pageData.file

pageData.file.ext = parsed.extname.slice(1)
const ext = pageData.file.ext

// Determine require path
pageData.requirePath = slash(path.relative(`${directory}/pages`, page))

// Make sure slashes on parsed.dirname are correct for Windows
parsed.dirname = slash(parsed.dirname)

// Load data for each file type.
// TODO use webpack-require to ensure data loaded
// here (in node context) is consistent with what's loaded
// in the browser.
let data
if (ext === 'md') {
const rawData = frontMatter(fs.readFileSync(page, 'utf-8'))
data = objectAssign({}, rawData.attributes)
pageData.data = data
} else if (ext === 'html') {
const html = fs.readFileSync(page, 'utf-8')
data = objectAssign({}, htmlFrontMatter(html), { body: html })
pageData.data = data
} else {
data = {}
}

// Determine path for page (unless it's a file that starts with an
// underscore as these don't become pages).
if (!(parsed.name.slice(0, 1) === '_')) {
if (data.path) {
// Path was hardcoded.
pageData.path = data.path
} else if (rewritePath) {
pageData.path = rewritePath(parsed, pageData)
}

// If the above didn't set a path, set our own.
if (!pageData.path) {
// If this is an index page or template, it's path is /foo/bar/
if (parsed.name === 'index' || parsed.name === 'template') {
if (parsed.dirname === '') {
pageData.path = '/'
} else {
pageData.path = `/${parsed.dirname}/`
}
// Else if not an index, create a path like /foo/bar/
// and rely upon static-site-generator-webpack-plugin to add index.html
} else {
if (parsed.dirname === '') {
pageData.path = `/${parsed.name}/`
} else {
pageData.path = `/${parsed.dirname}/${parsed.name}/`
}
}
}

// Set the "template path"
} else if (parsed.name === '_template') {
pageData.templatePath = `/${parsed.dirname}/`
}

pagesData.push(pageData)
pagesData.push(buildPage(directory, page))
})

debug(`globbed ${pagesData.length} pages`)
Expand Down
9 changes: 8 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
"yaml-loader": "^0.1.0"
},
"devDependencies": {
"ava": "^0.14.0",
"babel-cli": "^6.6.5",
"babel-eslint": "^6.0.0",
"eslint": "^2.4.0",
Expand Down Expand Up @@ -109,7 +110,13 @@
"scripts": {
"build": "babel lib --out-dir dist/",
"lint": "eslint --ext .js,.jsx --ignore-pattern dist .",
"test": "npm run lint",
"test": "node_modules/.bin/ava",
"watch": "babel -w lib --out-dir dist/"
},
"ava": {
"require": [
"babel-register"
],
"babel": "inherit"
}
}
56 changes: 56 additions & 0 deletions test/utils/build-page/path-resolver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import test from 'ava'
import path from 'path'
import { startsWith } from 'lodash'
import pathResolver from '../../../lib/utils/build-page/path-resolver'

test('it returns an object', t => {
const pagePath = '/'
const result = pathResolver(pagePath)
t.truthy(result)
t.is(typeof result, 'object')
})

test('it has a require path', t => {
const pagePath = '/a-blog-post/index.md'
const result = pathResolver(pagePath)
t.truthy(result.requirePath)
t.is(typeof result.requirePath, 'string')
})

test('it does not has a path if the name start with _', t => {
t.is(pathResolver('/_metadata.js').path, undefined)
t.is(pathResolver('/_template.html.erb').path, undefined)
t.is(pathResolver('/_notapage.json').path, undefined)
})

test('it has a path if the name doesnt start with _', t => {
t.truthy(pathResolver('/2015/back-to-the-future.md').path)
t.truthy(pathResolver('/my-first-blog.md').path)
t.truthy(pathResolver('/index.md').path)
})

test('it has a templatePath if the name is _template', t => {
const pagePath = '/_template.js'
const result = pathResolver(pagePath)
t.truthy(result.templatePath)
t.is(typeof result.templatePath, 'string')
})

test('it does not have a templatePath if not a _template', t => {
t.is(pathResolver('/index.md').templatePath, undefined)
t.is(pathResolver('/another-page.toml').templatePath, undefined)
t.is(pathResolver('/something-else/good-stuff.html').templatePath, undefined)
})

test('the directory name has / slashes', t => {
const pagePath = '/2016/testing-middleman-sites-with-capybara/index.md'
const result = pathResolver(pagePath)

t.is(result.file.dirname, path.posix.normalize(result.file.dirname))
t.is(result.file.dirname, '/2016/testing-middleman-sites-with-capybara')
})

test('the ext doesnt have a leading .', t => {
const result = pathResolver('/index.md')
t.false(startsWith(result.file.ext, '.'))
})
58 changes: 58 additions & 0 deletions test/utils/build-page/url-resolver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import test from 'ava'
import urlResolver from '../../../lib/utils/build-page/url-resolver'

test('returns undefined when filename starts with _', t => {
const parsedPath = { name: '_notapage' }
const data = {}
const pagePath = urlResolver(data, parsedPath)
t.true(pagePath === undefined)
})

test('uses the path from page data', t => {
const parsedPath = { name: 'page', dirname: 'a-directory/' }
const data = { path: '/page-at-root' }
const pagePath = urlResolver(data, parsedPath)
t.is(pagePath, '/page-at-root')
})

test('removes index from path', t => {
const parsedPath = { name: 'index', dirname: 'foo/bar' }
const data = {}
const pagePath = urlResolver(data, parsedPath)
t.is(pagePath, '/foo/bar/')
})

test('removes template from path', t => {
const parsedPath = { name: 'template', dirname: 'foo/bar' }
const data = {}
const pagePath = urlResolver(data, parsedPath)
t.is(pagePath, '/foo/bar/')
})

test('template at root has root path', t => {
const parsedPath = { name: 'template', dirname: '' }
const data = {}
const pagePath = urlResolver(data, parsedPath)
t.is(pagePath, '/')
})

test('index at root has root path', t => {
const parsedPath = { name: 'index', dirname: '' }
const data = {}
const pagePath = urlResolver(data, parsedPath)
t.is(pagePath, '/')
})

test('if not an index create a path like /foo/bar/', t => {
const parsedPath = { name: 'creating-static-websites', dirname: 'blog/2016' }
const data = {}
const pagePath = urlResolver(data, parsedPath)
t.is(pagePath, '/blog/2016/creating-static-websites/')
})

test('if not an index create a path like /foo/bar/', t => {
const parsedPath = { name: 'about-us', dirname: '' }
const data = {}
const pagePath = urlResolver(data, parsedPath)
t.is(pagePath, '/about-us/')
})