├── .gitignore
├── .npmrc
├── .travis.yml
├── example
├── .gitignore
├── .npmrc
├── assets
│ └── basic.png
├── content
│ ├── about
│ │ ├── example.png
│ │ ├── example.png.txt
│ │ └── index.txt
│ └── index.txt
├── index.js
├── package.json
└── src
│ ├── design
│ └── index.js
│ ├── stores
│ └── content.js
│ └── views
│ ├── custom.js
│ ├── index.js
│ ├── main.js
│ └── notfound.js
├── greenkeeper.json
├── index.js
├── lib
├── defaults.js
├── index.js
├── readFile.js
├── readFileSync.js
├── readFiles.js
├── readFilesSync.js
├── readPage.js
├── readPageSync.js
├── readSite.js
└── readSiteSync.js
├── package.json
├── readme.md
├── test.js
├── transform.js
└── utils
├── content.js
├── file.js
└── page.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | dist/
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | node_js:
2 | - '7'
3 | - '8'
4 | sudo: false
5 | language: node_js
6 | env:
7 | - CXX=g++-4.8
8 | addons:
9 | apt:
10 | sources:
11 | - ubuntu-toolchain-r-test
12 | packages:
13 | - g++-4.8
14 | script: npm run test
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | dist/
--------------------------------------------------------------------------------
/example/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
--------------------------------------------------------------------------------
/example/assets/basic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jondashkyle/nanocontent/0549fefc53960344fa68fd463854400c48408357/example/assets/basic.png
--------------------------------------------------------------------------------
/example/content/about/example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jondashkyle/nanocontent/0549fefc53960344fa68fd463854400c48408357/example/content/about/example.png
--------------------------------------------------------------------------------
/example/content/about/example.png.txt:
--------------------------------------------------------------------------------
1 | title: Custom meta
--------------------------------------------------------------------------------
/example/content/about/index.txt:
--------------------------------------------------------------------------------
1 | title: About
2 | ----
3 | view: custom
4 | ----
5 | text:
6 |
7 | Some example text
--------------------------------------------------------------------------------
/example/content/index.txt:
--------------------------------------------------------------------------------
1 | title: Example
2 | ----
3 | text: yeah *whatsup*
--------------------------------------------------------------------------------
/example/index.js:
--------------------------------------------------------------------------------
1 | var css = require('sheetify')
2 | var hypha = require('hypha')
3 | var choo = require('choo')
4 | css('./src/design/index.js')
5 |
6 | var site = hypha.readSiteSync('./content', {
7 | parent: '/content'
8 | })
9 |
10 | var app = choo()
11 |
12 | // content and routes
13 | app.use(require('./src/stores/content')(site))
14 | app.route('*', require('./src/views/notfound'))
15 |
16 | // export and mount
17 | if (module.parent) module.exports = app
18 | else app.mount('body')
19 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hypha-example",
3 | "version": "1.0.0",
4 | "description": "nice",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "bankai start"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "bel": "^6.0.0",
14 | "choo": "^6.5.1",
15 | "gr8": "^3.1.3",
16 | "markdown-it": "^8.4.0",
17 | "object-keys": "^1.0.11",
18 | "object-values": "^2.0.0",
19 | "sheetify": "^7.3.2",
20 | "xtend": "^4.0.1"
21 | },
22 | "devDependencies": {
23 | "bankai": "^9.0.2"
24 | },
25 | "browserify": {
26 | "transform": [
27 | "../transform.js"
28 | ]
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/example/src/design/index.js:
--------------------------------------------------------------------------------
1 | var gr8 = require('gr8')
2 |
3 | var utils = [ ]
4 |
5 | var colors = {
6 | white: '#fff',
7 | black: '#000'
8 | }
9 |
10 | utils.push({
11 | prop: 'font-family',
12 | join: '-',
13 | vals: {
14 | sans: '-apple-system, BlinkMacSystemFont, sans-serif'
15 | }
16 | })
17 |
18 | utils.push({
19 | prop: { bgc: 'background-color' },
20 | join: '-',
21 | vals: colors
22 | })
23 |
24 | utils.push({
25 | prop: { fc: 'color' },
26 | join: '-',
27 | vals: colors
28 | })
29 |
30 | var gr8css = gr8({
31 | utils: utils
32 | })
33 |
34 | module.exports = gr8css
35 |
--------------------------------------------------------------------------------
/example/src/stores/content.js:
--------------------------------------------------------------------------------
1 | var objectKeys = require('object-keys')
2 | var xtend = require('xtend')
3 | var views = require('../views')
4 |
5 | module.exports = store
6 |
7 | function store (site) {
8 | return function content (state, emitter, app) {
9 | state.content = { }
10 |
11 | objectKeys(site).forEach(function (path) {
12 | // set view and extend state
13 | var page = site[path]
14 | var view = views[page.view] || views.main
15 | state.content[page.url] = page
16 |
17 | app.route(page.url, function (state, emit) {
18 | return view(xtend(state, { page: page }), emit)
19 | })
20 | })
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/example/src/views/custom.js:
--------------------------------------------------------------------------------
1 | var html = require('choo/html')
2 |
3 | module.exports = view
4 |
5 | function view (state, emit) {
6 | var page = state.page || { }
7 | return html`
8 |
9 | custom ${page.name}
10 | back
11 |
12 | `
13 | }
14 |
--------------------------------------------------------------------------------
/example/src/views/index.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | main: require('./main'),
3 | notfound: require('./notfound'),
4 | custom: require('./custom')
5 | }
6 |
--------------------------------------------------------------------------------
/example/src/views/main.js:
--------------------------------------------------------------------------------
1 | var objectValues = require('object-values')
2 | var Markdown = require('markdown-it')
3 | var html = require('choo/html')
4 | var raw = require('bel/raw')
5 | var md = new Markdown()
6 |
7 | module.exports = view
8 |
9 | function view (state, emit) {
10 | var page = state.page || { }
11 |
12 | return html`
13 |
14 |
15 |
name ${page.name || 'no name'}
16 |
title ${page.title || 'Untitled'}
17 |
text ${raw(md.render(page.text || 'No content'))}
18 | ${page.pages ? pages() : ''}
19 |
20 |
21 | `
22 |
23 | function pages () {
24 | return objectValues(page.pages).map(function (subpage) {
25 | return html`${subpage.name}`
26 | })
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/example/src/views/notfound.js:
--------------------------------------------------------------------------------
1 | var html = require('choo/html')
2 |
3 | module.exports = view
4 |
5 | function view (state, emit) {
6 | return html`
7 |
8 | not found
9 |
10 | `
11 | }
12 |
--------------------------------------------------------------------------------
/greenkeeper.json:
--------------------------------------------------------------------------------
1 | {
2 | "groups": {
3 | "default": {
4 | "packages": [
5 | "example/package.json",
6 | "package.json"
7 | ]
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var xtend = require('xtend')
2 | var fs = require('fs')
3 | var lib = require('./lib')
4 |
5 | module.exports = {
6 | readFile: readFile,
7 | readFileSync: readFileSync,
8 | readFiles: readFiles,
9 | readFilesSync: readFilesSync,
10 | readPage: readPage,
11 | readPageSync: readPageSync,
12 | readSite: readSite,
13 | readSiteSync: readSiteSync
14 | }
15 |
16 | function readFile (pathFile, opts, callback) {
17 | opts = xtend({ fs: fs }, opts)
18 | return lib.readFile(pathFile, opts, callback)
19 | }
20 |
21 | function readFileSync (pathFile, opts, callback) {
22 | opts = xtend({ fs: fs }, opts)
23 | return lib.readFileSync(pathFile, opts)
24 | }
25 |
26 | function readFiles (files, pathSite, opts, callback) {
27 | opts = xtend({ fs: fs }, opts)
28 | return lib.readFiles(files, pathSite, opts, callback)
29 | }
30 |
31 | function readFilesSync (pathFile, opts, callback) {
32 | opts = xtend({ fs: fs }, opts)
33 | return lib.readFilesSync(pathFile, opts)
34 | }
35 |
36 | function readPage (pathPage, opts, callback) {
37 | opts = xtend({ fs: fs }, opts)
38 | return lib.readPage(pathPage, opts, callback)
39 | }
40 |
41 | function readPageSync (pathPage, opts, callback) {
42 | opts = xtend({ fs: fs }, opts)
43 | return lib.readPageSync(pathPage, opts)
44 | }
45 |
46 | function readSite (pathSite, opts, callback) {
47 | opts = xtend({ fs: fs }, opts)
48 | return lib.readSite(pathSite, opts, callback)
49 | }
50 |
51 | function readSiteSync (pathSite, opts, callback) {
52 | opts = xtend(opts, { fs: fs })
53 | return lib.readSiteSync(pathSite, opts)
54 | }
55 |
--------------------------------------------------------------------------------
/lib/defaults.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | reservedKeys: ['files', 'pages', 'url', 'name', 'path'],
3 | ignore: /(^[.#]|(?:__|~)$)/,
4 | encoding: 'utf8',
5 | file: 'index.txt',
6 | filetypes: {
7 | asset: ['.css', '.js'],
8 | archive: ['.zip'],
9 | audio: ['.mp3', '.wav', '.aiff'],
10 | document: ['.pdf'],
11 | image: ['.gif', '.jpg', '.jpeg', '.png', '.svg'],
12 | video: ['.mp4', '.mov'],
13 | font: ['.ttf', '.otf', '.woff', '.woff2']
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | readPage: require('./readPage'),
3 | readPageSync: require('./readPageSync'),
4 | readFile: require('./readFile'),
5 | readFiles: require('./readFiles'),
6 | readSite: require('./readSite'),
7 | readSiteSync: require('./readSiteSync')
8 | }
9 |
--------------------------------------------------------------------------------
/lib/readFile.js:
--------------------------------------------------------------------------------
1 | var assert = require('assert')
2 |
3 | var utilFile = require('../utils/file')
4 | var readPage = require('./readPage')
5 |
6 | module.exports = readFile
7 |
8 | async function readFile (pathFile, opts) {
9 | assert.equal(typeof pathFile, 'string', 'arg1: pathFile must be type string')
10 | assert.equal(typeof opts, 'object', 'arg2: opts must be type object')
11 | assert.equal(typeof opts.fs, 'object', 'arg2: opts.fs must be type object')
12 |
13 | if (!utilFile.isFile(pathFile)) {
14 | return readPage(pathFile, opts)
15 | } else {
16 | return false
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/lib/readFileSync.js:
--------------------------------------------------------------------------------
1 | var assert = require('assert')
2 |
3 | var readPageSync = require('./readPageSync')
4 | var utilFile = require('../utils/file')
5 |
6 | module.exports = readFileSync
7 |
8 | function readFileSync (pathFile, opts) {
9 | assert.equal(typeof pathFile, 'string', 'arg1: pathFile must be type string')
10 | assert.equal(typeof opts, 'object', 'arg2: opts must be type object')
11 | assert.equal(typeof opts.fs, 'object', 'arg2: opts.fs must be type object')
12 |
13 | if (!utilFile.isFile(pathFile)) {
14 | return readPageSync(pathFile, opts)
15 | } else {
16 | return false
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/lib/readFiles.js:
--------------------------------------------------------------------------------
1 | var assert = require('assert')
2 |
3 | var defaults = require('./defaults')
4 | var readFile = require('./readFile')
5 |
6 | module.exports = readFiles
7 |
8 | async function readFiles (files, pathSite, opts) {
9 | assert.equal(typeof files, 'object', 'arg1: files must be type object')
10 | assert.equal(typeof opts, 'object', 'arg2: opts must be type object')
11 | assert.equal(typeof opts.fs, 'object', 'arg2: opts.fs must be type object')
12 |
13 | var output = { }
14 |
15 | // read the index
16 | if (files.indexOf(pathSite) < 0) {
17 | files.push(pathSite)
18 | }
19 |
20 | await Promise.all(files.map(read))
21 | return output
22 |
23 | async function read (pathFile) {
24 | var content = await readFile(pathFile, opts)
25 | if (content && !content.name.match(defaults.ignore)) {
26 | output[content.url] = content
27 | }
28 | return content
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/lib/readFilesSync.js:
--------------------------------------------------------------------------------
1 | var assert = require('assert')
2 |
3 | var readFileSync = require('./readFileSync')
4 | var defaults = require('./defaults')
5 |
6 | module.exports = readFilesSync
7 |
8 | function readFilesSync (files, pathSite, opts) {
9 | assert.equal(typeof files, 'object', 'arg1: files must be type object')
10 | assert.equal(typeof opts, 'object', 'arg2: opts must be type object')
11 | assert.equal(typeof opts.fs, 'object', 'arg2: opts.fs must be type object')
12 |
13 | var output = { }
14 |
15 | // read the index
16 | if (files.indexOf(pathSite) < 0) {
17 | files.push(pathSite)
18 | }
19 |
20 | files.forEach(function (pathFile) {
21 | if (typeof opts.onFile === 'function') opts.onFile(pathFile)
22 | var content = readFileSync(pathFile, opts)
23 | if (content && !content.name.match(defaults.ignore)) {
24 | output[content.url] = content
25 | }
26 | })
27 |
28 | return output
29 | }
30 |
--------------------------------------------------------------------------------
/lib/readPage.js:
--------------------------------------------------------------------------------
1 | var slash = require('normalize-path')
2 | var assert = require('assert')
3 | var smarkt = require('smarkt')
4 | var xtend = require('xtend')
5 | var path = require('path')
6 | var pify = require('pify')
7 |
8 | var utilFile = require('../utils/file')
9 | var defaults = require('./defaults')
10 |
11 | module.exports = readPage
12 |
13 | async function readPage (pathPage, opts) {
14 | assert.equal(typeof pathPage, 'string', 'arg1: pathPage must be type string')
15 | assert.equal(typeof opts, 'object', 'arg2: opts must be type object')
16 | assert.equal(typeof opts.fs, 'object', 'arg2: opts.fs must be type object')
17 |
18 | var fs = opts.fs.url ? opts.fs : pify(opts.fs) // web api or node
19 | var parse = typeof opts.parse === 'function' ? opts.parse : smarkt.parse
20 | var fileIndex = opts.file || defaults.file
21 | var fileExtname = path.extname(fileIndex)
22 | var filetypes = opts.filetypes || defaults.filetypes
23 | var pathRoot = opts.pathRoot || ''
24 | var pathUrl = utilFile.formatUrl(pathPage, pathRoot, opts.parent)
25 | var encoding = opts.encoding || defaults.encoding
26 | var content = await getContent()
27 | var childrenInput = await getChildren()
28 | var children = childrenInput
29 | .filter(file => utilFile.filterFile(file, fileIndex))
30 | .reduce(utilFile.sortChildren, { files: [], pages: [] })
31 | var files = await getFiles(children.files)
32 | var pages = getPages(children.pages)
33 |
34 | return xtend(content, {
35 | name: path.basename(pathPage),
36 | path: utilFile.formatUrl(pathPage, pathRoot),
37 | url: pathUrl,
38 | files: files,
39 | pages: pages
40 | })
41 |
42 | async function getChildren () {
43 | try {
44 | return await fs.readdir(pathPage)
45 | } catch (err) {
46 | return []
47 | }
48 | }
49 |
50 | async function getContent () {
51 | try {
52 | var content
53 | content = await fs.readFile(slash(path.join(pathPage, fileIndex)), encoding)
54 | content = parse(content)
55 | return content
56 | } catch (err) {
57 | return ''
58 | }
59 | }
60 |
61 | async function getFiles (files) {
62 | var result = { }
63 | await Promise.all(files.map(read))
64 | return result
65 |
66 | async function read (pathFile) {
67 | var fileParsed = utilFile.getFileMeta({
68 | pathFile: pathFile,
69 | pathRoot: pathRoot,
70 | filetypes: filetypes,
71 | pathParent: pathPage,
72 | pathSource: opts.source,
73 | pathSiteParent: opts.parent
74 | })
75 |
76 | try {
77 | var fileMeta = pathFile + fileExtname
78 | var pathMeta = path.join(pathPage, fileMeta)
79 | var text = await fs.readFile(pathMeta, encoding)
80 | // set
81 | result[fileParsed.filename] = xtend(parse(text), fileParsed)
82 | files.splice(files.indexOf(fileMeta), 1)
83 | // cleanup
84 | delete result[fileMeta]
85 | return text
86 | } catch (err) {
87 | if (fileParsed.filename) {
88 | result[fileParsed.filename] = fileParsed
89 | }
90 | return Promise.resolve()
91 | }
92 | }
93 | }
94 |
95 | function getPages (pages) {
96 | return pages.reduce(function (result, pathSubpage) {
97 | var fileParsed = utilFile.getFileMeta({
98 | pathRoot: pathRoot,
99 | pathFile: pathSubpage,
100 | filetypes: filetypes,
101 | pathParent: pathPage,
102 | pathSiteParent: opts.parent
103 | })
104 |
105 | if (fileParsed.name) result[fileParsed.name] = fileParsed
106 | return result
107 | }, {})
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/lib/readPageSync.js:
--------------------------------------------------------------------------------
1 | var slash = require('normalize-path')
2 | var assert = require('assert')
3 | var smarkt = require('smarkt')
4 | var xtend = require('xtend')
5 | var path = require('path')
6 |
7 | var utilFile = require('../utils/file')
8 | var defaults = require('./defaults')
9 |
10 | module.exports = readPageSync
11 |
12 | function readPageSync (pathPage, opts) {
13 | assert.equal(typeof pathPage, 'string', 'arg1: pathPage must be type string')
14 | assert.equal(typeof opts, 'object', 'arg2: opts must be type object')
15 | assert.equal(typeof opts.fs, 'object', 'arg2: opts.fs must be type object')
16 |
17 | var fs = opts.fs
18 | var parse = typeof opts.parse === 'function' ? opts.parse : smarkt.parse
19 | var fileIndex = opts.file || defaults.file
20 | var fileExtname = path.extname(fileIndex)
21 | var filetypes = opts.filetypes || defaults.filetypes
22 | var pathRoot = opts.pathRoot || ''
23 | var pathUrl = utilFile.formatUrl(pathPage, pathRoot, opts.parent)
24 | var encoding = opts.encoding || defaults.encoding
25 | var content = getContent()
26 | var children = getChildren()
27 | .filter(file => utilFile.filterFile(file, fileIndex))
28 | .reduce(utilFile.sortChildren, { files: [ ], pages: [ ] })
29 | var files = getFiles(children.files)
30 | var pages = getPages(children.pages)
31 |
32 | return xtend(content, {
33 | name: path.basename(pathPage),
34 | path: utilFile.formatUrl(pathPage, pathRoot),
35 | url: pathUrl,
36 | files: files,
37 | pages: pages
38 | })
39 |
40 | function getChildren () {
41 | try {
42 | return fs.readdirSync(pathPage)
43 | } catch (err) {
44 | return [ ]
45 | }
46 | }
47 |
48 | function getContent () {
49 | try {
50 | var content
51 | content = fs.readFileSync(slash(path.join(pathPage, fileIndex)), encoding)
52 | content = parse(content)
53 | return content
54 | } catch (err) {
55 | return ''
56 | }
57 | }
58 |
59 | function getFiles (files) {
60 | return files.reduce(function (result, pathFile) {
61 | var fileParsed = utilFile.getFileMeta({
62 | pathFile: pathFile,
63 | pathRoot: pathRoot,
64 | filetypes: filetypes,
65 | pathParent: pathPage,
66 | pathSiteParent: opts.parent
67 | })
68 |
69 | try {
70 | var fileMeta = pathFile + fileExtname
71 | var text = fs.readFileSync(slash(path.join(pathPage, fileMeta)), encoding)
72 | // set
73 | result[fileParsed.filename] = xtend(parse(text), fileParsed)
74 | files.splice(files.indexOf(fileMeta), 1)
75 | // cleanup
76 | delete result[fileMeta]
77 | } catch (err) {
78 | if (fileParsed.filename) {
79 | result[fileParsed.filename] = fileParsed
80 | }
81 | }
82 |
83 | return result
84 | }, { })
85 | }
86 |
87 | function getPages (pages) {
88 | return pages.reduce(function (result, pathSubpage) {
89 | var fileParsed = utilFile.getFileMeta({
90 | pathRoot: pathRoot,
91 | pathFile: pathSubpage,
92 | filetypes: filetypes,
93 | pathParent: pathPage,
94 | pathSource: opts.source,
95 | pathSiteParent: opts.parent
96 | })
97 |
98 | if (fileParsed.name) result[fileParsed.name] = fileParsed
99 | return result
100 | }, { })
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/lib/readSite.js:
--------------------------------------------------------------------------------
1 | var slash = require('normalize-path')
2 | var assert = require('assert')
3 | var path = require('path')
4 | var pify = require('pify')
5 | var glob = pify(require('glob'))
6 |
7 | var readFiles = require('./readFiles')
8 |
9 | module.exports = readSite
10 |
11 | async function readSite (pathSite, opts) {
12 | assert.equal(typeof pathSite, 'string', 'arg1: pathSite must be type string')
13 | assert.equal(typeof opts, 'object', 'arg2: opts must be type object')
14 | assert.equal(typeof opts.fs, 'object', 'arg2: opts.fs must be type object')
15 |
16 | // parent
17 | if (opts.parent === true) opts.parent = pathSite
18 |
19 | // loop through the files
20 | var files = await glob(slash(path.join(pathSite, '/**/*')))
21 | return readFiles(files, pathSite, opts)
22 | }
23 |
--------------------------------------------------------------------------------
/lib/readSiteSync.js:
--------------------------------------------------------------------------------
1 | var slash = require('normalize-path')
2 | var assert = require('assert')
3 | var path = require('path')
4 | var glob = require('glob')
5 |
6 | var readFilesSync = require('./readFilesSync')
7 |
8 | module.exports = readSiteSync
9 |
10 | function readSiteSync (pathSite, opts) {
11 | assert.equal(typeof pathSite, 'string', 'arg1: pathSite must be type string')
12 | assert.equal(typeof opts, 'object', 'arg2: opts must be type object')
13 | assert.equal(typeof opts.fs, 'object', 'arg2: opts.fs must be type object')
14 |
15 | // parent
16 | if (opts.parent === true) opts.parent = pathSite
17 |
18 | // loop through the files
19 | var files = glob.sync(slash(path.join(pathSite, '/**/*')))
20 | return readFilesSync(files, pathSite, opts)
21 | }
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nanocontent",
3 | "version": "0.4.6",
4 | "description": "read a directory of content into an object",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "standard; ava"
8 | },
9 | "keywords": [],
10 | "author": "Jon-Kyle (http://jon-kyle.com)",
11 | "license": "Apache-2.0",
12 | "bugs": {
13 | "url": "https://github.com/jondashkyle/nanocontent/issues"
14 | },
15 | "homepage": "https://github.com/jondashkyle/nanocontent#readme",
16 | "repository": {
17 | "type": "git",
18 | "url": "git+https://github.com/jondashkyle/nanocontent.git"
19 | },
20 | "dependencies": {
21 | "glob": "^7.1.2",
22 | "js-yaml": "^3.10.0",
23 | "normalize-path": "^3.0.0",
24 | "object-keys": "^1.0.11",
25 | "object-values": "^2.0.0",
26 | "pify": "^3.0.0",
27 | "smarkt": "0.0.6",
28 | "static-module": "^2.2.5",
29 | "through2": "^2.0.3",
30 | "xtend": "^4.0.1"
31 | },
32 | "devDependencies": {
33 | "ava": "^0.25.0",
34 | "standard": "^11.0.1"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | nanocontent
2 |
3 |
11 |
12 |
13 |
14 | **work in progress...**
15 |
16 | Introducing flat content state. Read directories of content into an object.
17 |
18 | - Store all of your content in a directory
19 | - Each directory is a page
20 | - The content for each page is stored in a text file
21 | - Your file system becomes a router!
22 | - Pairs nicely with [`nanopage`](https://github.com/jondashkyle/nanopage) for traversing object structure
23 |
24 | ```
25 | npm install nanocontent --save
26 | ```
27 |
28 | ## Usage
29 |
30 | Format some plain text files using [smarkt](https://github.com/jondashkyle/smarkt) fields.
31 |
32 | ```
33 | title: Technopastoral
34 | ----
35 | date: January 19, 2038
36 | ----
37 | tags:
38 | - garden
39 | - engineering
40 | ----
41 | text: To deprogram oneself necessitates keeping to very specific schedules, which are what Foucault, once again, described as techniques of the self, echoing Seneca.
42 | ```
43 |
44 | Organize them within a directory structure alongside media assets.
45 |
46 | ```
47 | /content
48 | /about
49 | index.txt
50 | /blog
51 | /38-01-19-technopastoral
52 | index.txt
53 | header.jpg
54 | index.txt
55 | ```
56 |
57 | Turn the directory into an object.
58 |
59 | ```js
60 | var nanocontent = require('nanocontent')
61 | var site = nanocontent.readSiteSync('./content')
62 | ```
63 |
64 | Each directory becomes a path containing a sub-object of the content in your text file.
65 |
66 | ```
67 | {
68 | '/': { },
69 | '/about': { },
70 | '/blog': { },
71 | '/blog/30-01-19-technopastoral': { }
72 | }
73 | ```
74 |
75 | Map over the object keys to add routes to a router, then pass the content object. Huzzah.
76 |
77 | ## API
78 |
79 | #### `.readFile(path, [options])`
80 |
81 | #### `.readFiles(files, pathSite, [options])`
82 |
83 | #### `.readPage(path, [options])`
84 |
85 | #### `.readSite(path, [options])`
86 |
87 | #### `.readFileSync(path, [options])`
88 |
89 | #### `.readFilesSync(files, pathSite, [options])`
90 |
91 | #### `.readPageSync(path, [options])`
92 |
93 | #### `.readSiteSync(path, [options])`
94 |
95 | ## Options
96 |
97 | #### `fs`
98 |
99 | Provide a custom implementation of `fs`. Ensure the `mkdir` `readdir` `writeFile` and `readFile` methods are available. This is useful for replacing Node’s `fs` with Dat’s API, for instance.
100 |
101 | #### `parse`
102 |
103 | Substitute `smarkt` with your own parser. Must be able to transform a plain text file into a JSON object.
104 |
105 | #### `parent`
106 |
107 | Remove part of the `url` for pretty printing. For example, if your content lives in `/content`, but you don’t want to prefix all of your `urls` with `/content`, use `parent` to clean it up. Value can be a string or boolean. If `true`, the `path` of your initial call is used.
108 |
109 | ## Transform
110 |
111 | ```
112 | browserify -t nanocontent/transform
113 | ```
114 |
115 | A browserify transform located at `nanocontent/transform` is included to staticly inline the module output.
116 |
117 | ## Example
118 |
119 | A demo site is included. Open the `nanocontent/example` dir and `npm install`. The example uses [Bankai](https://github.com/choojs/bankai). Run `npm start` to spin up a Bankai server and mess around. Run `bankai build` to build a fully static site.
120 |
121 | ## Todo
122 |
123 | - [ ] Tests
124 | - [ ] Async callback/promise fallback
125 | - [x] Modularize read function for JSON/Smarkt/Custom
126 |
--------------------------------------------------------------------------------
/test.js:
--------------------------------------------------------------------------------
1 | var test = require('ava')
2 | var hypha = require('.')
3 |
4 | test('readPageSync works', function (t) {
5 | var page = hypha.readPageSync('example/content/about')
6 | t.is(page.title, 'About')
7 | t.is(page.view, 'custom')
8 | })
9 |
10 | test('readPage works', async function (t) {
11 | var page = await hypha.readPage('example/content/about')
12 | t.is(page.title, 'About')
13 | t.is(page.view, 'custom')
14 | })
15 |
16 | test('readPageSync and readPage outputs are the same', async function (t) {
17 | var syncPage = hypha.readPageSync('example/content/about')
18 | var asyncPage = await hypha.readPage('example/content/about')
19 | t.deepEqual(syncPage, asyncPage)
20 | })
21 |
22 | test('readSiteSync works', function (t) {
23 | var site = hypha.readSiteSync('example/content')
24 | t.is(site['/example/content'].title, 'Example')
25 | t.is(site['/example/content/about'].title, 'About')
26 | })
27 |
28 | test('readSiteSync and readSite outputs are the same', async function (t) {
29 | var syncSite = hypha.readSiteSync('example/content')
30 | var asyncSite = await hypha.readSite('example/content')
31 | t.deepEqual(syncSite, asyncSite)
32 | })
33 |
34 | test('readSiteSync and readSite outputs are the same with parent option', async function (t) {
35 | var syncSite = hypha.readSiteSync('example/content', { parent: true })
36 | var asyncSite = await hypha.readSite('example/content', { parent: true })
37 | t.deepEqual(syncSite, asyncSite)
38 | })
39 |
--------------------------------------------------------------------------------
/transform.js:
--------------------------------------------------------------------------------
1 | var staticModule = require('static-module')
2 | var through = require('through2')
3 | var path = require('path')
4 |
5 | var nanocontent = require('.')
6 |
7 | module.exports = transform
8 |
9 | function transform (filename) {
10 | if (/\.json$/.test(filename)) return through()
11 |
12 | var vars = {
13 | __filename: filename,
14 | __dirname: path.dirname(filename)
15 | }
16 |
17 | var sm = staticModule({
18 | nanocontent: {
19 | readPageSync: function (pathPage, opts) {
20 | opts = opts || { }
21 | opts.pathRoot = opts.pathRoot || vars.__dirname
22 | opts.parent = typeof opts.parent !== 'undefined' ? opts.parent : true
23 |
24 | var pathDir = path.isAbsolute(pathPage) ? pathPage : path.join(vars.__dirname, pathPage)
25 | var pageSync = nanocontent.readPageSync(pathDir, opts)
26 |
27 | var stream = through()
28 | stream.push(JSON.stringify(pageSync, { }, 2))
29 | stream.push(null)
30 | return stream
31 | },
32 | readSiteSync: function readDir (pathSite, opts) {
33 | opts = opts || { }
34 | opts.pathRoot = opts.pathRoot || vars.__dirname
35 | opts.parent = typeof opts.parent !== 'undefined' ? opts.parent : true
36 |
37 | opts.onFile = function (pathFile) {
38 | sm.emit('file', pathFile)
39 | }
40 |
41 | var pathDir = path.isAbsolute(pathSite) ? pathSite : path.join(vars.__dirname, pathSite)
42 | var siteSync = nanocontent.readSiteSync(pathDir, opts)
43 |
44 | var stream = through()
45 | stream.push(JSON.stringify(siteSync, { }, 2))
46 | stream.push(null)
47 | return stream
48 | }
49 | }
50 | }, {
51 | vars: vars,
52 | varModules: { path: path }
53 | })
54 |
55 | return sm
56 | }
57 |
--------------------------------------------------------------------------------
/utils/content.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jondashkyle/nanocontent/0549fefc53960344fa68fd463854400c48408357/utils/content.js
--------------------------------------------------------------------------------
/utils/file.js:
--------------------------------------------------------------------------------
1 | var objectKeys = require('object-keys')
2 | var assert = require('assert')
3 | var slash = require('normalize-path')
4 | var path = require('path')
5 |
6 | module.exports = {
7 | formatUrl: formatUrl,
8 | filterFile: filterFile,
9 | getFileType: getFileType,
10 | getFileMeta: getFileMeta,
11 | sortChildren: sortChildren,
12 | isFile: isFile
13 | }
14 |
15 | function sortChildren (result, active) {
16 | var ext = path.extname(active)
17 | result = result || { }
18 | result.files = result.files || [ ]
19 | result.pages = result.pages || [ ]
20 |
21 | if (ext) result.files.push(active)
22 | else result.pages.push(active)
23 |
24 | return result
25 | }
26 |
27 | function filterFile (file, index) {
28 | if (file === '.DS_Store') return false
29 | if (/(^[.#]|(?:__|~)$)/.test(file)) return false
30 | if (file.indexOf(index) >= 0) return false
31 | if (file.indexOf('src') >= 0) return false
32 | return true
33 | }
34 |
35 | function getFileType (extension, filetypes) {
36 | return objectKeys(filetypes)
37 | .reduce(function (result, value, i, source) {
38 | if (result) return result
39 |
40 | if (
41 | filetypes[value] &&
42 | filetypes[value].indexOf(extension) >= 0
43 | ) {
44 | return value
45 | }
46 |
47 | if (i >= source.length) return 'unknown'
48 | }, '')
49 | }
50 |
51 | function isFile (pathFile) {
52 | assert.equal(typeof pathFile, 'string', 'enoki: arg1 pathFile must be type string')
53 | return path.extname(pathFile) !== ''
54 | }
55 |
56 | function getFileMeta (opts) {
57 | assert.equal(typeof opts, 'object', 'enoki: arg1 opts must be type object')
58 | assert.equal(typeof opts.pathFile, 'string', 'enoki: arg1 opts.pathFile must be type string')
59 | assert.equal(typeof opts.pathParent, 'string', 'enoki: arg1 opts.pathParent must be type string')
60 | assert.equal(typeof opts.pathRoot, 'string', 'enoki: arg1 opts.pathRoot must be type string')
61 | assert.equal(typeof opts.filetypes, 'object', 'enoki: arg1 opts.filetypes must be type string')
62 |
63 | var output = { }
64 | var ext = path.extname(opts.pathFile)
65 | output.name = path.basename(opts.pathFile, ext)
66 | output.path = formatUrl(path.join('/', opts.pathParent, '/', opts.pathFile), opts.pathRoot)
67 | output.url = formatUrl(path.join('/', opts.pathParent, '/', opts.pathFile), opts.pathRoot, opts.pathSiteParent)
68 | output.source = opts.pathSource ? (opts.pathSource + output.path) : output.path
69 |
70 | if (ext) {
71 | output.extension = ext.toLowerCase()
72 | output.filename = path.basename(opts.pathFile)
73 | output.type = getFileType(output.extension, opts.filetypes)
74 | }
75 |
76 | return output
77 | }
78 |
79 | function formatUrl (pathFile, pathRoot, pathSiteParent) {
80 | pathFile = pathFile.replace(pathRoot, '')
81 | if (pathSiteParent) pathFile = pathFile.replace(pathSiteParent, '')
82 | pathFile = slash(path.join('/', pathFile))
83 | return pathFile || '/'
84 | }
85 |
--------------------------------------------------------------------------------
/utils/page.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jondashkyle/nanocontent/0549fefc53960344fa68fd463854400c48408357/utils/page.js
--------------------------------------------------------------------------------