initial commit
This commit is contained in:
		
							parent
							
								
									3f3b892240
								
							
						
					
					
						commit
						f31f6ea1a4
					
				
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1,3 +1,6 @@ | |||||||
|  | node_modules | ||||||
|  | bower_components | ||||||
|  | 
 | ||||||
| # Logs | # Logs | ||||||
| logs | logs | ||||||
| *.log | *.log | ||||||
|  | |||||||
							
								
								
									
										40
									
								
								bower.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								bower.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,40 @@ | |||||||
|  | { | ||||||
|  |   "name": "deardesi", | ||||||
|  |   "version": "1.0.0", | ||||||
|  |   "authors": [ | ||||||
|  |     "AJ ONeal <awesome@coolaj86.com>" | ||||||
|  |   ], | ||||||
|  |   "description": "A blogging platform in the browser. Wow!", | ||||||
|  |   "main": "deardesi.js", | ||||||
|  |   "moduleType": [ | ||||||
|  |     "globals", | ||||||
|  |     "node" | ||||||
|  |   ], | ||||||
|  |   "keywords": [ | ||||||
|  |     "dear", | ||||||
|  |     "desi", | ||||||
|  |     "deardesi", | ||||||
|  |     "blog", | ||||||
|  |     "blogging", | ||||||
|  |     "platform", | ||||||
|  |     "browser" | ||||||
|  |   ], | ||||||
|  |   "license": "Apache2", | ||||||
|  |   "homepage": "http://github.com/coolaj86/deardesi", | ||||||
|  |   "ignore": [ | ||||||
|  |     "**/.*", | ||||||
|  |     "node_modules", | ||||||
|  |     "bower_components", | ||||||
|  |     "test", | ||||||
|  |     "tests" | ||||||
|  |   ], | ||||||
|  |   "dependencies": { | ||||||
|  |     "mustache": "~0.8.2", | ||||||
|  |     "bluebird": "~2.5.2", | ||||||
|  |     "rsvp": "~3.0.16", | ||||||
|  |     "escape-string-regexp": "~1.0.2", | ||||||
|  |     "marked": "~0.3.2", | ||||||
|  |     "js-yaml": "~3.2.5", | ||||||
|  |     "path": "~3.46.1" | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										216
									
								
								deardesi.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								deardesi.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,216 @@ | |||||||
|  | ;(function (exports) { | ||||||
|  |   'use strict'; | ||||||
|  | 
 | ||||||
|  |   //require('require-yaml');
 | ||||||
|  | 
 | ||||||
|  |   var PromiseA      = exports.Promise       || require('bluebird').Promise | ||||||
|  |     , path          = exports.path          || require('path') | ||||||
|  |     , Mustache      = exports.Mustache      || require('mustache') | ||||||
|  |     , marked        = exports.marked        || require('marked') | ||||||
|  |     , forEachAsync  = exports.forEachAsync  || require('foreachasync').forEachAsync | ||||||
|  |     , sha1sum       = exports.sha1sum       || require('./lib/deardesi-node').sha1sum | ||||||
|  |     , frontmatter   = exports.frontmatter   || require('./lib/frontmatter').Frontmatter | ||||||
|  |     , safeResolve   = exports.safeResolve   || require('./lib/deardesi-utils').safeResolve | ||||||
|  |     , getStats      = exports.getStats      || require('./lib/deardesi-node').getStats | ||||||
|  |     , getContents   = exports.getContents   || require('./lib/deardesi-node').getContents | ||||||
|  |     ; | ||||||
|  | 
 | ||||||
|  |   function getCollections(blogbase, ignorable, collectionnames) { | ||||||
|  |     var collectiondir | ||||||
|  |       , collectiondirs = [] | ||||||
|  |       , lost = [] | ||||||
|  |       , found = [] | ||||||
|  |       , errors = [] | ||||||
|  |       ; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     collectionnames.forEach(function (collectionname) { | ||||||
|  |       collectiondir = safeResolve(_dirname, collectionname); | ||||||
|  | 
 | ||||||
|  |       if (!collectiondir) { | ||||||
|  |         return PromiseA.reject(new Error("Please update your config.yml: " + collectionname + " is outside of '" + _dirname + "'")); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       collectiondirs.push({ name: collectionname, path: collectiondir }); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     return getFolders(collectiondirs, { recursive: true, limit: 5, stats: true }).then(function (stats) { | ||||||
|  |       collectiondirs.forEach(function (collection) { | ||||||
|  |         if (!stats[collection.path]) { | ||||||
|  |           errors.push({ | ||||||
|  |             collection: collection | ||||||
|  |           , message: "server did not return success or error for " + collection.path + ':\n' + JSON.stringify(stats) | ||||||
|  |           }); | ||||||
|  |         } | ||||||
|  |         else if (!stats[collection.path].type) { | ||||||
|  |           lost.push(collection); | ||||||
|  |         } | ||||||
|  |         else if ('directory' !== stats[collection.path].type) { | ||||||
|  |           errors.push({ | ||||||
|  |             collection: collection | ||||||
|  |           , message: collection.path + " is not a directory (might be a symbolic link)" | ||||||
|  |           }); | ||||||
|  |         } else { | ||||||
|  |           found.push(collection); | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       return { | ||||||
|  |         lost: lost | ||||||
|  |       , found: found | ||||||
|  |       , errors: errors | ||||||
|  |       }; | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function showCollectionNotes(notes) { | ||||||
|  |     if (notes.lost.length) { | ||||||
|  |       console.warn("WARNING: these collections you specified couldn't be found"); | ||||||
|  |       notes.lost.forEach(function (node) { | ||||||
|  |         console.warn('? ' + node.name); | ||||||
|  |       }); | ||||||
|  |       console.log(''); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (notes.found.length) { | ||||||
|  |       console.log("Will compile these collections"); | ||||||
|  |       notes.found.forEach(function (node) { | ||||||
|  |         console.log('+ ' + node.name); | ||||||
|  |       }); | ||||||
|  |       console.log(''); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function getLayouts() { | ||||||
|  |     // TODO
 | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function updatePage(pagedir, node, lstat, data) { | ||||||
|  |     var parts = frontmatter.parse(data) | ||||||
|  |       , meta | ||||||
|  |       , html | ||||||
|  |       , view | ||||||
|  |       ; | ||||||
|  | 
 | ||||||
|  |     if (!parts.yml) { | ||||||
|  |       console.error("Could not parse frontmatter for " + node); | ||||||
|  |       console.error(parts.frontmatter); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (/\.(html|htm)$/.test(node)) { | ||||||
|  |       html = parts.body.trim(); | ||||||
|  |     } else if (/\.(md|markdown|mdown|mkdn|mkd|mdwn|mdtxt|mdtext)$/.test(node)) { | ||||||
|  |       console.log('parsing markdown...'); | ||||||
|  |       html = marked(parts.body.trim()); | ||||||
|  |     } else { | ||||||
|  |       console.error('unknown parser for ' + node); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     meta = { | ||||||
|  |       mtime: lstat.mtime | ||||||
|  |     , ymlsum: sha1sum(parts.frontmatter.trim()) | ||||||
|  |     , textsum: sha1sum(parts.body.trim()) | ||||||
|  |     , htmlsum: sha1sum(html) | ||||||
|  |     , filesum: sha1sum(data) | ||||||
|  |     , filename: node | ||||||
|  |     , filepath: pagedir | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     /* | ||||||
|  |     // TODO
 | ||||||
|  |     db.getCached(meta).error(function () { | ||||||
|  |       // TODO rebuild and save
 | ||||||
|  |     }); | ||||||
|  |     */ | ||||||
|  | 
 | ||||||
|  |     // TODO meta.layout
 | ||||||
|  |     view = { | ||||||
|  |       page: parts.yml | ||||||
|  |     , content: html | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     console.log(node); | ||||||
|  |     console.log(parts.frontmatter); | ||||||
|  |     console.log(parts.yml); //Mustache.render(pagetpl, view));
 | ||||||
|  |     //console.log(meta.mtime.valueOf(), meta.ymlsum, meta.textsum, node);
 | ||||||
|  | 
 | ||||||
|  |     return meta; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function templatePosts() { | ||||||
|  |     var pagetpl | ||||||
|  |       , defaulttpl | ||||||
|  |       ; | ||||||
|  | 
 | ||||||
|  |     // TODO declare path to theme
 | ||||||
|  |     pagetpl = frontmatter.parse(fs.readFileSync(path.join(config.theme, 'layouts', 'page.html'), 'utf8')); | ||||||
|  |     defaulttpl = frontmatter.parse(fs.readFileSync(path.join(config.theme, 'layouts', 'default.html'), 'utf8')); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function getCollection() { | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   console.log(''); | ||||||
|  |   console.log(''); | ||||||
|  |   console.log('loading caches...'); | ||||||
|  | 
 | ||||||
|  |   getMetaCache().then(function (db) { | ||||||
|  |     console.log('last update: ' + (db.lastUpdate && new Date(db.lastUpdate) || 'never')); | ||||||
|  | 
 | ||||||
|  |     console.log('checking for local updates...'); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     // TODO get layouts here
 | ||||||
|  |     return getCollections('.', Object.keys(config.collections)).then(function (notes) { | ||||||
|  |       showCollectionNotes(notes); | ||||||
|  | 
 | ||||||
|  |       return notes.found; | ||||||
|  |     }).then(function (found) { | ||||||
|  |       var metas = [] | ||||||
|  |         ; | ||||||
|  | 
 | ||||||
|  |       return forEachAsync(found, function (collection) { | ||||||
|  |         begintime = Date.now(); | ||||||
|  |         console.log('begin', ((begintime - starttime) / 1000).toFixed(4)); | ||||||
|  | 
 | ||||||
|  |         return fs.readdirAsync(collection.path).then(function (nodes) { | ||||||
|  | 
 | ||||||
|  |           // TODO look for companion yml file aside html|md|jade
 | ||||||
|  |           nodes = nodes.filter(function (node) { | ||||||
|  |             // TODO have handlers accept or reject extensions in the order they are registered
 | ||||||
|  |             if (!/\.(htm|html|md|markdown|mdown|mkdn|mkd|jade)$/.test(node)) { | ||||||
|  |               console.warn("ignoring " + collection.name + '/' + node + " (unknown filetype processor)"); | ||||||
|  |               return false; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             return true; | ||||||
|  |           }); | ||||||
|  | 
 | ||||||
|  |           return forEachAsync(nodes, function (pagename) { | ||||||
|  |             var pagepath = path.join(collection.path, pagename) | ||||||
|  |               ; | ||||||
|  | 
 | ||||||
|  |             // TODO: support walking deep
 | ||||||
|  |             // TODO: test .html, .md, etc
 | ||||||
|  |             return fs.lstatAsync(pagepath).then(function (lstat) { | ||||||
|  |               // no funny business allowed
 | ||||||
|  |               if (!lstat.isFile()) { | ||||||
|  |                 return; | ||||||
|  |               } | ||||||
|  | 
 | ||||||
|  |               return fs.readFileAsync(nodepath, 'utf8').then(function (data) { | ||||||
|  |                 updatePage(pagedir, node, lstat, data); | ||||||
|  |               }); | ||||||
|  |             }); | ||||||
|  |           }); | ||||||
|  |         }).then(function () { | ||||||
|  |           console.log('doneish', ((Date.now() - begintime) / 1000).toFixed(4)); | ||||||
|  |         }); | ||||||
|  |       }); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | }('undefined' !== typeof exports && exports || window)); | ||||||
							
								
								
									
										19
									
								
								index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								index.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | 
 | ||||||
|  | <html> | ||||||
|  |   <head> | ||||||
|  |     <title>Dear Desi</title> | ||||||
|  |     <script src="./bower_components/bluebird/js/browser/bluebird.js"></script> | ||||||
|  |     <script src="./bower_components/mustache/mustache.js"></script> | ||||||
|  |     <script src="./bower_components/marked/lib/marked.js"></script> | ||||||
|  |     <script src="./bower_components/js-yaml/dist/js-yaml.js"></script> | ||||||
|  |     <script src="./bower_components/path/path.js"></script> | ||||||
|  |     <script src="./lib/deardesi-utils.js"></script> | ||||||
|  |     <script src="./lib/verify-config.js"></script> | ||||||
|  |     <script src="./lib/deardesi-browser.js"></script> | ||||||
|  |     <script src="./lib/frontmatter.js"></script> | ||||||
|  |     <script src="./deardesi.js"></script> | ||||||
|  |   </head> | ||||||
|  |   <body> | ||||||
|  |     <p>Open up the console, fool!</p> | ||||||
|  |   </body> | ||||||
|  | </html> | ||||||
							
								
								
									
										7
									
								
								lib/convert-ruhoh-config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								lib/convert-ruhoh-config.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | |||||||
|  | 'use strict'; | ||||||
|  | 
 | ||||||
|  | module.exports.convert = function () { | ||||||
|  |   console.error("I haven't implemented a ruhoh -> nuhoh converter yet, but it's not very hard to do."); | ||||||
|  |   console.error("see https://github.com/coolaj86/nuhoh/tree/master/MIGRATE.md"); | ||||||
|  |   throw new Error('Not Implemented.'); | ||||||
|  | }; | ||||||
							
								
								
									
										128
									
								
								lib/deardesi-browser.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								lib/deardesi-browser.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,128 @@ | |||||||
|  | /*jshint -W054 */ | ||||||
|  | var tmpglobal | ||||||
|  |   ; | ||||||
|  | 
 | ||||||
|  | try { | ||||||
|  |   tmpglobal = new Function('return this')(); | ||||||
|  | }  catch(e) { | ||||||
|  |   tmpglobal = window; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ;(function (exports) { | ||||||
|  |   'use strict'; | ||||||
|  | 
 | ||||||
|  |   // Chrome, Firefox, and even MSIE11+ all support crypto
 | ||||||
|  |   var crypto = window.crypto || window.msCrypto | ||||||
|  |     , algos | ||||||
|  |     ; | ||||||
|  | 
 | ||||||
|  |   // convenience mappings for common digest algorithms
 | ||||||
|  |   algos = { | ||||||
|  |     'sha1': 'SHA-1' | ||||||
|  |   , 'sha256': 'SHA-256' | ||||||
|  |   , 'sha512': 'SHA-512' | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   // The function to generate a sha1sum is the same as generating any digest
 | ||||||
|  |   // but here's a shortcut function anyway
 | ||||||
|  |   function sha1sum(str) { | ||||||
|  |     return hashsum('sha1', str); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // a more general convenience function
 | ||||||
|  |   function hashsum(hash, str) { | ||||||
|  |       // you have to convert from string to array buffer
 | ||||||
|  |     var ab | ||||||
|  |       // you have to represent the algorithm as an object 
 | ||||||
|  |       , algo = { name: algos[hash] } | ||||||
|  |       ; | ||||||
|  | 
 | ||||||
|  |     if ('string' === typeof str) { | ||||||
|  |       ab = str2ab(str); | ||||||
|  |     } else { | ||||||
|  |       ab = str; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // All crypto digest methods return a promise
 | ||||||
|  |     return crypto.subtle.digest(algo, ab).then(function (digest) { | ||||||
|  |       // you have to convert the ArrayBuffer to a DataView and then to a hex String
 | ||||||
|  |       return ab2hex(digest); | ||||||
|  |     }).catch(function (e) { | ||||||
|  |       // if you specify an unsupported digest algorithm or non-ArrayBuffer, you'll get an error
 | ||||||
|  |       console.error('sha1sum ERROR'); | ||||||
|  |       console.error(e); | ||||||
|  |       throw e; | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // convert from arraybuffer to hex
 | ||||||
|  |   function ab2hex(ab) { | ||||||
|  |     var dv = new DataView(ab) | ||||||
|  |       , i | ||||||
|  |       , len | ||||||
|  |       , hex = '' | ||||||
|  |       , c | ||||||
|  |       ; | ||||||
|  | 
 | ||||||
|  |     for (i = 0, len = dv.byteLength; i < len; i += 1) { | ||||||
|  |       c = dv.getUint8(i).toString(16); | ||||||
|  | 
 | ||||||
|  |       if (c.length < 2) { | ||||||
|  |         c = '0' + c; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       hex += c; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return hex; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // convert from string to arraybuffer
 | ||||||
|  |   function str2ab(stringToEncode, insertBom) { | ||||||
|  |     stringToEncode = stringToEncode.replace(/\r\n/g,"\n"); | ||||||
|  | 
 | ||||||
|  |     var utftext = [] | ||||||
|  |       , n | ||||||
|  |       , c | ||||||
|  |       ; | ||||||
|  | 
 | ||||||
|  |     if (true === insertBom)  { | ||||||
|  |       utftext[0] =  0xef; | ||||||
|  |       utftext[1] =  0xbb; | ||||||
|  |       utftext[2] =  0xbf; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     for (n = 0; n < stringToEncode.length; n += 1) { | ||||||
|  | 
 | ||||||
|  |       c = stringToEncode.charCodeAt(n); | ||||||
|  | 
 | ||||||
|  |       if (c < 128) { | ||||||
|  |           utftext[utftext.length]= c; | ||||||
|  |       } | ||||||
|  |       else if((c > 127) && (c < 2048)) { | ||||||
|  |           utftext[utftext.length] = (c >> 6) | 192; | ||||||
|  |           utftext[utftext.length] = (c & 63) | 128; | ||||||
|  |       } | ||||||
|  |       else { | ||||||
|  |           utftext[utftext.length] = (c >> 12) | 224; | ||||||
|  |           utftext[utftext.length] = ((c >> 6) & 63) | 128; | ||||||
|  |           utftext[utftext.length] = (c & 63) | 128; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  |     return new Uint8Array(utftext).buffer; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   exports.hashsum = hashsum; | ||||||
|  |   exports.sha1sum = sha1sum; | ||||||
|  | }('undefined' !== typeof exports && exports || tmpglobal)); | ||||||
|  | 
 | ||||||
|  | ;(function () { | ||||||
|  |   'use strict'; | ||||||
|  | 
 | ||||||
|  |   exports.getStats | ||||||
|  |   exports.getContents | ||||||
|  |   exports.getMetaCache | ||||||
|  |   exports.getContentCache | ||||||
|  |   //require('./db').create(path.join(_dirname, 'db.json'))
 | ||||||
|  | }()); | ||||||
							
								
								
									
										9
									
								
								lib/deardesi-node.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								lib/deardesi-node.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | |||||||
|  | 'use strict'; | ||||||
|  | 
 | ||||||
|  | var PromiseA = require('bluebird').Promise | ||||||
|  |   , secretutils = require('secret-utils') | ||||||
|  |   ; | ||||||
|  | 
 | ||||||
|  | module.exports.sha1sum = function (str) { | ||||||
|  |   return PromiseA.resolve( secretutils.hashsum('sha1', str) ); | ||||||
|  | }; | ||||||
							
								
								
									
										23
									
								
								lib/deardesi-utils.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								lib/deardesi-utils.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | |||||||
|  | ;(function (exports) { | ||||||
|  |   'use strict'; | ||||||
|  | 
 | ||||||
|  |   var path  = exports.path  || require('path') | ||||||
|  |     ; | ||||||
|  | 
 | ||||||
|  |   function escapeRegExp(str) { | ||||||
|  |     return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function safeResolve(basename, target) { | ||||||
|  |     basename = path.resolve(basename); | ||||||
|  | 
 | ||||||
|  |     var targetname = path.resolve(basename, target) | ||||||
|  |       , re = new RegExp('^' + escapeRegExp(basename) + '(/|$)') | ||||||
|  |       ; | ||||||
|  | 
 | ||||||
|  |     return re.test(targetname) && targetname; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   exports.safeResolve = safeResolve; | ||||||
|  |   exports.escapeRegExp = escapeRegExp; | ||||||
|  | }('undefined' !== typeof exports && exports || window)); | ||||||
							
								
								
									
										103
									
								
								lib/frontmatter.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								lib/frontmatter.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,103 @@ | |||||||
|  | /*jshint -W054 */ | ||||||
|  | ;(function (exports) { | ||||||
|  |   'use strict'; | ||||||
|  | 
 | ||||||
|  |   var YAML = {} | ||||||
|  |     ; | ||||||
|  | 
 | ||||||
|  |   YAML.parse = exports.jsyaml.load || require('jsyaml').load; | ||||||
|  |   //YAML.parse = require('yaml').eval;
 | ||||||
|  |   //YAML.parse2 = require('yamljs').parse;
 | ||||||
|  | 
 | ||||||
|  |   function readFrontMatter(text) { | ||||||
|  |     var lines | ||||||
|  |       , line | ||||||
|  |       , padIndent = '' | ||||||
|  |       , ymllines = [] | ||||||
|  |       ; | ||||||
|  | 
 | ||||||
|  |     lines = text.split(/\n/); | ||||||
|  |     line = lines.shift(); | ||||||
|  | 
 | ||||||
|  |     if (!line.match(/^---\s*$/)) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // our yaml parser can't handle objects
 | ||||||
|  |     // that start without indentation, so
 | ||||||
|  |     // we can add it if this is the case
 | ||||||
|  |     if (lines[0] && lines[0].match(/^\S/)) { | ||||||
|  |       padIndent = ''; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     while (true) { | ||||||
|  |       line = lines.shift(); | ||||||
|  | 
 | ||||||
|  |       // premature end-of-file (unsupported yaml)
 | ||||||
|  |       if (!line && '' !== line) { | ||||||
|  |         ymllines = []; | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       // end-of-yaml front-matter
 | ||||||
|  |       if (line.match(/^---\s*$/)) { | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       if (line) { | ||||||
|  |         // supported yaml
 | ||||||
|  |         ymllines.push(padIndent + line);  | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     // XXX can't be sorted because arrays get messed up
 | ||||||
|  |     //ymllines.sort();
 | ||||||
|  |     if (ymllines) { | ||||||
|  |       return '---\n' + ymllines.join('\n'); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function separateText(text, fm) { | ||||||
|  |     var len | ||||||
|  |       , yml | ||||||
|  |       ; | ||||||
|  | 
 | ||||||
|  |     yml = readFrontMatter(fm); | ||||||
|  |     // strip frontmatter from text, if any
 | ||||||
|  |     // including trailing '---' (which is accounted for by the added '\n')
 | ||||||
|  |     if (yml) { | ||||||
|  |       len = fm.split(/\n/).length; | ||||||
|  |     } else { | ||||||
|  |       len = 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return text.split(/\n/).slice(len).join('\n'); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function parseText(text) { | ||||||
|  |     var fm = readFrontMatter(text) | ||||||
|  |       , body = separateText(text, fm) | ||||||
|  |       , yml | ||||||
|  |       ; | ||||||
|  | 
 | ||||||
|  |     try { | ||||||
|  |       yml = YAML.parse(fm); | ||||||
|  |     } catch(e) { | ||||||
|  |       //
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return { | ||||||
|  |       yml: yml | ||||||
|  |     , frontmatter: fm | ||||||
|  |     , body: body | ||||||
|  |     }; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   exports.Frontmatter.Frontmatter = exports.Frontmatter = {}; | ||||||
|  |   exports.Frontmatter.readText = readFrontMatter; | ||||||
|  |   exports.Frontmatter.separateText = separateText; | ||||||
|  |   exports.Frontmatter.parse = parseText; | ||||||
|  | }('undefined' !== typeof exports && exports || window)); | ||||||
							
								
								
									
										56
									
								
								lib/verify-config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								lib/verify-config.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,56 @@ | |||||||
|  | 'use strict'; | ||||||
|  | 
 | ||||||
|  | module.export.verify = function (conf) { | ||||||
|  |   if (!conf.NuhohSpec) { | ||||||
|  |     throw new Error("missing key NuhohSpec"); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if (!conf.production) { | ||||||
|  |     throw new Error("missing key production"); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if (!conf.production.canonical_url) { | ||||||
|  |     throw new Error("missing key production.canonical_url"); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if (!conf.production.base_path) { | ||||||
|  |     throw new Error("missing key production.base_path"); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if (!conf.development) { | ||||||
|  |     throw new Error("missing key development"); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if (!conf.development.compiled_path) { | ||||||
|  |     throw new Error("missing key development.compiled_path"); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if (!Array.isArray(conf.collections)) { | ||||||
|  |     if (conf.posts) { | ||||||
|  |       console.error("Please indent and nest 'posts' under the key 'collection' to continue"); | ||||||
|  |     } | ||||||
|  |     throw new Error("missing key 'collections'."); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if (!conf.themes) { | ||||||
|  |     if (conf.twitter) { | ||||||
|  |       console.error("Please indent and nest 'twitter' under the key 'themes' to continue"); | ||||||
|  |     } | ||||||
|  |     throw new Error("missing key 'themes'"); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if (!conf.themes.default) { | ||||||
|  |     if (conf.twitter) { | ||||||
|  |       console.error("Please set themes.default to 'twitter'"); | ||||||
|  |     } | ||||||
|  |     throw new Error("missing key 'themes.default'"); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if (!conf.root) { | ||||||
|  |     throw new Error("missing key root"); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if (!conf.widgets) { | ||||||
|  |     throw new Error("missing key root"); | ||||||
|  |   } | ||||||
|  | }; | ||||||
							
								
								
									
										28
									
								
								lib/walk.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								lib/walk.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | |||||||
|  | 'use strict'; | ||||||
|  | 
 | ||||||
|  | var PromiseA = require('bluebird').Promise | ||||||
|  |   , path = require('path') | ||||||
|  |   , walk = require('walk') | ||||||
|  |   , walker | ||||||
|  |   ; | ||||||
|  | 
 | ||||||
|  | function getFs(parent, sub) { | ||||||
|  |   // TODO safe
 | ||||||
|  |   var trueRoot = path.resolve(parent, sub) | ||||||
|  |     ; | ||||||
|  | 
 | ||||||
|  |   return new PromiseA(function (resolve) { | ||||||
|  |     walker = walk.walk('posts'); | ||||||
|  |     walker.on('directories', function (root, stat, next) { | ||||||
|  |       console.log(root, stat); | ||||||
|  |       next(); | ||||||
|  |     }); | ||||||
|  |     walker.on('files', function (root, stat, next) { | ||||||
|  |       //console.log(root, stat);
 | ||||||
|  |       next(); | ||||||
|  |     }); | ||||||
|  |     walker.on('end', function () { | ||||||
|  |       console.log('done'); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | } | ||||||
							
								
								
									
										47
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,47 @@ | |||||||
|  | { | ||||||
|  |   "name": "deardesi", | ||||||
|  |   "version": "0.1.0", | ||||||
|  |   "description": "An in-browser knockoff of the Ruhoh static blog generator. (similar to Jekyll, Octopress, Nanoc, etc)", | ||||||
|  |   "main": "server.js", | ||||||
|  |   "scripts": { | ||||||
|  |     "test": "echo \"Error: no test specified\" && exit 1" | ||||||
|  |   }, | ||||||
|  |   "repository": { | ||||||
|  |     "type": "git", | ||||||
|  |     "url": "git@github.com:coolaj86/deardesi.git" | ||||||
|  |   }, | ||||||
|  |   "keywords": [ | ||||||
|  |     "dear", | ||||||
|  |     "deardesi", | ||||||
|  |     "desi", | ||||||
|  |     "ruhoh", | ||||||
|  |     "ruhoh", | ||||||
|  |     "blog", | ||||||
|  |     "static", | ||||||
|  |     "jekyll", | ||||||
|  |     "octopress", | ||||||
|  |     "nanoc" | ||||||
|  |   ], | ||||||
|  |   "author": "AJ ONeal", | ||||||
|  |   "license": "Apache2", | ||||||
|  |   "bugs": { | ||||||
|  |     "url": "https://github.com/coolaj86/deardesi/issues" | ||||||
|  |   }, | ||||||
|  |   "homepage": "https://github.com/coolaj86/deardesi", | ||||||
|  |   "dependencies": { | ||||||
|  |     "bluebird": "^2.5.3", | ||||||
|  |     "circular-json": "^0.1.6", | ||||||
|  |     "escape-string-regexp": "^1.0.2", | ||||||
|  |     "foreachasync": "^5.0.2", | ||||||
|  |     "json2yaml": "^1.0.3", | ||||||
|  |     "markdown": "^0.5.0", | ||||||
|  |     "marked": "^0.3.2", | ||||||
|  |     "mustache": "^1.0.0", | ||||||
|  |     "require-yaml": "0.0.1", | ||||||
|  |     "require-yamljs": "^1.0.1", | ||||||
|  |     "secret-utils": "^1.0.2", | ||||||
|  |     "walk": "^2.3.5", | ||||||
|  |     "yaml": "^0.2.3", | ||||||
|  |     "yamljs": "^0.2.1" | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										41
									
								
								server.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								server.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | |||||||
|  | 'use strict'; | ||||||
|  | 
 | ||||||
|  | var connect = require('connect') | ||||||
|  |   , query = require('connect-query') | ||||||
|  |   , bodyParser = require('body-parser') | ||||||
|  |   , serveStatic = require('serve-static') | ||||||
|  |   , app = connect() | ||||||
|  |   ; | ||||||
|  | 
 | ||||||
|  | app | ||||||
|  |   .use('/api/fs', query()) | ||||||
|  |   .use('/api/fs', bodyParser.json()) | ||||||
|  |   .use('/api/fs', function (req, res, next) { | ||||||
|  |       if (!(/^GET$/i.test(req.method) || /^GET$/i.test(req.query._method))) { | ||||||
|  |         next(); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       /* | ||||||
|  |       return forEachAsync(collectiondirs, function (collection) { | ||||||
|  |         return fs.lstatAsync(collection.path).then(function (stat) { | ||||||
|  |           if (!stat.isDirectory()) { | ||||||
|  |             //return;
 | ||||||
|  |           } | ||||||
|  | 
 | ||||||
|  |         }).error(function () { | ||||||
|  |         }); | ||||||
|  |       }).then(function () { | ||||||
|  |       }); | ||||||
|  |       */ | ||||||
|  | 
 | ||||||
|  |       res.end('not implemented'); | ||||||
|  |     }) | ||||||
|  |   .use('/api/fs', function (req, res, next) { | ||||||
|  |       next(); | ||||||
|  |       return; | ||||||
|  |     }) | ||||||
|  |   .use(serveStatic('.')) | ||||||
|  |   ; | ||||||
|  | 
 | ||||||
|  | module.exports = app; | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user