make Prettier
This commit is contained in:
		
							parent
							
								
									0909c8e9cc
								
							
						
					
					
						commit
						9131fb9a42
					
				
							
								
								
									
										1
									
								
								.prettierrc.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.prettierrc.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
{}
 | 
			
		||||
							
								
								
									
										94
									
								
								DATA.md
									
									
									
									
									
								
							
							
						
						
									
										94
									
								
								DATA.md
									
									
									
									
									
								
							@ -1,12 +1,10 @@
 | 
			
		||||
Data
 | 
			
		||||
====
 | 
			
		||||
# Data
 | 
			
		||||
 | 
			
		||||
Every template gets an object with the exact same structure - whether it's a template or a widget or a page or a post.
 | 
			
		||||
 | 
			
		||||
Here we only document Desirae's default behavior, but there are many objects added for compatibility with Ruhoh that are not documented.
 | 
			
		||||
 | 
			
		||||
config.yml vs site.yml
 | 
			
		||||
------
 | 
			
		||||
## config.yml vs site.yml
 | 
			
		||||
 | 
			
		||||
site.yml is for anything that changes the content of the site (navigation, title, analytic and ad ids, default author, etc)
 | 
			
		||||
 | 
			
		||||
@ -16,66 +14,60 @@ config.yml is for anything that doesn't change the site (from where to read dire
 | 
			
		||||
desi = {}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
desi
 | 
			
		||||
====
 | 
			
		||||
# desi
 | 
			
		||||
 | 
			
		||||
* `config` - literally `config.yml`, parsed
 | 
			
		||||
* `site` - literally `site.yml`, parsed
 | 
			
		||||
* `authors` - literally the authors from `authors/*.yml`, parsed
 | 
			
		||||
* `author` - the primary author of the site
 | 
			
		||||
* `env` - urls and paths for this build (be it production, development, staging, etc)
 | 
			
		||||
* `content` - pre-rendered content (i.e. content rendered into the post layout rendered into the default layout)
 | 
			
		||||
* `collection` - config related to this collection
 | 
			
		||||
* `entity` - the page, post, article, etc that is the focus of the present template process
 | 
			
		||||
* `themes` - all themes
 | 
			
		||||
* `theme` - the default theme
 | 
			
		||||
* `layout` - the selected layout for this theme
 | 
			
		||||
* `satch` - the selected swatch for this theme
 | 
			
		||||
* `categories` - all categories
 | 
			
		||||
* `tags` - all tags
 | 
			
		||||
* `styles` - ??? goes into the final template in the head
 | 
			
		||||
* `scripts` - ?? that goes into the final template just before the body close
 | 
			
		||||
- `config` - literally `config.yml`, parsed
 | 
			
		||||
- `site` - literally `site.yml`, parsed
 | 
			
		||||
- `authors` - literally the authors from `authors/*.yml`, parsed
 | 
			
		||||
- `author` - the primary author of the site
 | 
			
		||||
- `env` - urls and paths for this build (be it production, development, staging, etc)
 | 
			
		||||
- `content` - pre-rendered content (i.e. content rendered into the post layout rendered into the default layout)
 | 
			
		||||
- `collection` - config related to this collection
 | 
			
		||||
- `entity` - the page, post, article, etc that is the focus of the present template process
 | 
			
		||||
- `themes` - all themes
 | 
			
		||||
- `theme` - the default theme
 | 
			
		||||
- `layout` - the selected layout for this theme
 | 
			
		||||
- `satch` - the selected swatch for this theme
 | 
			
		||||
- `categories` - all categories
 | 
			
		||||
- `tags` - all tags
 | 
			
		||||
- `styles` - ??? goes into the final template in the head
 | 
			
		||||
- `scripts` - ?? that goes into the final template just before the body close
 | 
			
		||||
 | 
			
		||||
desi.entity
 | 
			
		||||
===========
 | 
			
		||||
# desi.entity
 | 
			
		||||
 | 
			
		||||
stuff
 | 
			
		||||
 | 
			
		||||
* `uuid`
 | 
			
		||||
* `title`
 | 
			
		||||
* `disqus_url`
 | 
			
		||||
* `disqus_identifier`
 | 
			
		||||
- `uuid`
 | 
			
		||||
- `title`
 | 
			
		||||
- `disqus_url`
 | 
			
		||||
- `disqus_identifier`
 | 
			
		||||
 | 
			
		||||
more stuff
 | 
			
		||||
 | 
			
		||||
* `type` - `post`, `page`, etc
 | 
			
		||||
* `authors` - literally the relevant authors from `authors/*.yml`, parsed
 | 
			
		||||
* `author` - the primary author of this entity
 | 
			
		||||
* `theme` - null or a non-default theme
 | 
			
		||||
* `layout` - null or a non-default layout for this theme
 | 
			
		||||
* `swatch` - null or a non-default swatch for this theme
 | 
			
		||||
* `categories`: []    // *all* categories in all collections
 | 
			
		||||
* `tags`: []    // *all* categories in all collections
 | 
			
		||||
* `production_canonical_url` the PRODUCTION canonical_url for this entity
 | 
			
		||||
* `production_url` the PRODUCTION url for this entity
 | 
			
		||||
* `production_path` the PRODUCTION path for this entity
 | 
			
		||||
* `url` the full url in the current environment (might be production, development, etc)
 | 
			
		||||
* `path` the non-host part (i.e. `/compiled_dev/articles/my-first-post.html`)
 | 
			
		||||
* `previous` the previous entity in this collection
 | 
			
		||||
* `next` the next entitiy in this collection
 | 
			
		||||
- `type` - `post`, `page`, etc
 | 
			
		||||
- `authors` - literally the relevant authors from `authors/*.yml`, parsed
 | 
			
		||||
- `author` - the primary author of this entity
 | 
			
		||||
- `theme` - null or a non-default theme
 | 
			
		||||
- `layout` - null or a non-default layout for this theme
 | 
			
		||||
- `swatch` - null or a non-default swatch for this theme
 | 
			
		||||
- `categories`: [] // _all_ categories in all collections
 | 
			
		||||
- `tags`: [] // _all_ categories in all collections
 | 
			
		||||
- `production_canonical_url` the PRODUCTION canonical_url for this entity
 | 
			
		||||
- `production_url` the PRODUCTION url for this entity
 | 
			
		||||
- `production_path` the PRODUCTION path for this entity
 | 
			
		||||
- `url` the full url in the current environment (might be production, development, etc)
 | 
			
		||||
- `path` the non-host part (i.e. `/compiled_dev/articles/my-first-post.html`)
 | 
			
		||||
- `previous` the previous entity in this collection
 | 
			
		||||
- `next` the next entitiy in this collection
 | 
			
		||||
 | 
			
		||||
NOTE: Plugins, widgets, etc SHOULD NOT modify config, site, authors, author, or env.
 | 
			
		||||
 | 
			
		||||
desi.posts
 | 
			
		||||
==========
 | 
			
		||||
# desi.posts
 | 
			
		||||
 | 
			
		||||
      , posts: { collated: desi.collated }
 | 
			
		||||
 | 
			
		||||
desi.config
 | 
			
		||||
===========
 | 
			
		||||
# desi.config
 | 
			
		||||
 | 
			
		||||
desi.site
 | 
			
		||||
===========
 | 
			
		||||
# desi.site
 | 
			
		||||
 | 
			
		||||
desi.env
 | 
			
		||||
===========
 | 
			
		||||
# desi.env
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										84
									
								
								ENTITY.md
									
									
									
									
									
								
							
							
						
						
									
										84
									
								
								ENTITY.md
									
									
									
									
									
								
							@ -2,61 +2,65 @@ This is what an entity looks like:
 | 
			
		||||
 | 
			
		||||
```yml
 | 
			
		||||
# inherited from File Entity
 | 
			
		||||
path              : My Posts/My-Old-Name.html
 | 
			
		||||
lastModifiedDate  : 2015-07-04T13:56:01Z
 | 
			
		||||
createdDate       : 2015-07-04T13:56:01Z
 | 
			
		||||
contents          : '...'           # whatever the file is
 | 
			
		||||
path: My Posts/My-Old-Name.html
 | 
			
		||||
lastModifiedDate: 2015-07-04T13:56:01Z
 | 
			
		||||
createdDate: 2015-07-04T13:56:01Z
 | 
			
		||||
contents: "..." # whatever the file is
 | 
			
		||||
 | 
			
		||||
# inherited from Collection Entity
 | 
			
		||||
name              : My-Old-Name.html
 | 
			
		||||
relativePath      : My Posts
 | 
			
		||||
ext               : .html
 | 
			
		||||
collection        : posts
 | 
			
		||||
name: My-Old-Name.html
 | 
			
		||||
relativePath: My Posts
 | 
			
		||||
ext: .html
 | 
			
		||||
collection: posts
 | 
			
		||||
 | 
			
		||||
# inherited from Content Entity
 | 
			
		||||
frontmatter       : '---\n...\n---' # frontmatter as a string
 | 
			
		||||
yml               : {}              # frontmatter, parsed
 | 
			
		||||
body              : 'I think ...'   # body, after frontmatter
 | 
			
		||||
frontmatter: '---\n...\n---' # frontmatter as a string
 | 
			
		||||
yml: {} # frontmatter, parsed
 | 
			
		||||
body: "I think ..." # body, after frontmatter
 | 
			
		||||
 | 
			
		||||
# inherited from Normalized Entity
 | 
			
		||||
title             : My Title        # yml.title | titlize(entity.name)
 | 
			
		||||
slug              : my-title        # slugify(title)
 | 
			
		||||
slug_path         : my-posts        # slugifyPath(relativePath)
 | 
			
		||||
title: My Title # yml.title | titlize(entity.name)
 | 
			
		||||
slug: my-title # slugify(title)
 | 
			
		||||
slug_path: my-posts # slugifyPath(relativePath)
 | 
			
		||||
 | 
			
		||||
year              : 2014
 | 
			
		||||
month             : 07
 | 
			
		||||
day               : 04
 | 
			
		||||
hour              : 13
 | 
			
		||||
twelve_hour       : 1
 | 
			
		||||
meridian          : pm
 | 
			
		||||
minute            : 22
 | 
			
		||||
year: 2014
 | 
			
		||||
month: 07
 | 
			
		||||
day: 04
 | 
			
		||||
hour: 13
 | 
			
		||||
twelve_hour: 1
 | 
			
		||||
meridian: pm
 | 
			
		||||
minute: 22
 | 
			
		||||
 | 
			
		||||
categories        : ['tech']
 | 
			
		||||
tags              : ['http','url','website']
 | 
			
		||||
categories: ["tech"]
 | 
			
		||||
tags:
 | 
			
		||||
  ["http", "url", "website"]
 | 
			
		||||
 | 
			
		||||
                    # includes index.html
 | 
			
		||||
relative_file     : /posts/foo/index.html
 | 
			
		||||
  # includes index.html
 | 
			
		||||
relative_file:
 | 
			
		||||
  /posts/foo/index.html
 | 
			
		||||
 | 
			
		||||
                    # excludes index.html
 | 
			
		||||
relative_href     : /posts/foo/
 | 
			
		||||
  # excludes index.html
 | 
			
		||||
relative_href:
 | 
			
		||||
  /posts/foo/
 | 
			
		||||
 | 
			
		||||
                    # actual url of this file, even if redirect
 | 
			
		||||
                    # excludes index.html
 | 
			
		||||
url               : http://dev.example.com/posts/foo/
 | 
			
		||||
  # actual url of this file, even if redirect
 | 
			
		||||
  # excludes index.html
 | 
			
		||||
url:
 | 
			
		||||
  http://dev.example.com/posts/foo/
 | 
			
		||||
 | 
			
		||||
                    # the appropriate url, even in a redirect or duplicate
 | 
			
		||||
                    # excludes index.html
 | 
			
		||||
canonical_url     : http://dev.example.com/posts/foo/
 | 
			
		||||
  # the appropriate url, even in a redirect or duplicate
 | 
			
		||||
  # excludes index.html
 | 
			
		||||
canonical_url:
 | 
			
		||||
  http://dev.example.com/posts/foo/
 | 
			
		||||
 | 
			
		||||
                    # production url, even in development (for disqus, etc)
 | 
			
		||||
                    # excludes index.html
 | 
			
		||||
production_url    : http://example.com/posts/foo/
 | 
			
		||||
  # production url, even in development (for disqus, etc)
 | 
			
		||||
  # excludes index.html
 | 
			
		||||
production_url: http://example.com/posts/foo/
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Note: The option `env.explicitIndexes` turns on `/index.html`. This option is automatically turned on when Dropbox is the host.
 | 
			
		||||
 | 
			
		||||
TODO
 | 
			
		||||
----
 | 
			
		||||
## TODO
 | 
			
		||||
 | 
			
		||||
* path relative from / in the browser
 | 
			
		||||
* path relative from base_path on the file system
 | 
			
		||||
- path relative from / in the browser
 | 
			
		||||
- path relative from base_path on the file system
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										34
									
								
								GLOSSARY.md
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								GLOSSARY.md
									
									
									
									
									
								
							@ -1,14 +1,12 @@
 | 
			
		||||
Glossary
 | 
			
		||||
========
 | 
			
		||||
# Glossary
 | 
			
		||||
 | 
			
		||||
Canonical URL
 | 
			
		||||
--------
 | 
			
		||||
base\_url + base\_path + permalink
 | 
			
		||||
## Canonical URL
 | 
			
		||||
 | 
			
		||||
Base URL
 | 
			
		||||
----
 | 
			
		||||
base_url + base_path + permalink
 | 
			
		||||
 | 
			
		||||
base\_url is the point of ownership
 | 
			
		||||
## Base URL
 | 
			
		||||
 | 
			
		||||
base_url is the point of ownership
 | 
			
		||||
 | 
			
		||||
In most cases that would be https://johndoe.com
 | 
			
		||||
 | 
			
		||||
@ -16,27 +14,25 @@ In some cases that might be https://school.edu/~/johndoe
 | 
			
		||||
 | 
			
		||||
It does NOT include a trailing /
 | 
			
		||||
 | 
			
		||||
Base Path
 | 
			
		||||
-----
 | 
			
		||||
## Base Path
 | 
			
		||||
 | 
			
		||||
base\_path is the blog directory
 | 
			
		||||
base_path is the blog directory
 | 
			
		||||
 | 
			
		||||
In most cases that would be / or /blog/
 | 
			
		||||
 | 
			
		||||
It DOES include BOTH a LEADING and TRAILING slash.
 | 
			
		||||
 | 
			
		||||
In the case of https://school.edu/~/johndoe/weblog, the base\_path would  be /weblog/.
 | 
			
		||||
In the case of https://school.edu/~/johndoe/weblog, the base_path would be /weblog/.
 | 
			
		||||
 | 
			
		||||
Permalink
 | 
			
		||||
------
 | 
			
		||||
## Permalink
 | 
			
		||||
 | 
			
		||||
The permalink is the permanent part of the URL, after the path to the blog.
 | 
			
		||||
 | 
			
		||||
For example:
 | 
			
		||||
 | 
			
		||||
  * http://blog.johndoe.com/articles/first-post.html the permalink is articles/first-post.html
 | 
			
		||||
  * http://johndoe.com/blog/articles/first-post.html the permalink is still articles/first-post.html
 | 
			
		||||
  * http://school.edu/~/johndoe/blog/articles/first-post.html the permalink is yet still articles/first-post.html
 | 
			
		||||
- http://blog.johndoe.com/articles/first-post.html the permalink is articles/first-post.html
 | 
			
		||||
- http://johndoe.com/blog/articles/first-post.html the permalink is still articles/first-post.html
 | 
			
		||||
- http://school.edu/~/johndoe/blog/articles/first-post.html the permalink is yet still articles/first-post.html
 | 
			
		||||
 | 
			
		||||
The permalink is ALWAYS RELATIVE (no leading slash)
 | 
			
		||||
 | 
			
		||||
@ -44,5 +40,5 @@ It is designed so that if you ever move your blog from one domain, point of owne
 | 
			
		||||
a very simple one-line redirect can be made to your webserver and all of the posts will end up in the right place
 | 
			
		||||
once again.
 | 
			
		||||
 | 
			
		||||
base\_url  the
 | 
			
		||||
permalink refers to 
 | 
			
		||||
base_url the
 | 
			
		||||
permalink refers to
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										201
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										201
									
								
								README.md
									
									
									
									
									
								
							@ -1,5 +1,4 @@
 | 
			
		||||
Did you mean DearDesi?
 | 
			
		||||
======================
 | 
			
		||||
# Did you mean DearDesi?
 | 
			
		||||
 | 
			
		||||
If you're looking for [DearDesi](http://dear.desi), the DIY blog platform for normal people
 | 
			
		||||
you should go to <http://dear.desi>.
 | 
			
		||||
@ -7,8 +6,7 @@ you should go to <http://dear.desi>.
 | 
			
		||||
Desirae (this repo) is the code that programmers to use to make DearDesi better
 | 
			
		||||
for everyone and to make Desirae-compatible blog platforms. (it's blog-ception!)
 | 
			
		||||
 | 
			
		||||
Desirae (v0.9)
 | 
			
		||||
=======
 | 
			
		||||
# Desirae (v0.9)
 | 
			
		||||
 | 
			
		||||
Desirae is a static webpage compiler written in JavaScript.
 | 
			
		||||
 | 
			
		||||
@ -19,18 +17,17 @@ It can also run entirely from the commandline (with io.js / node.js).
 | 
			
		||||
 | 
			
		||||
**Features:**
 | 
			
		||||
 | 
			
		||||
  * `JavaScript` - it's so stable it takes 10 years to get new any features.
 | 
			
		||||
    * Won't break every time you upgrade OS X and reinstall `brew` (*cough* ruby)
 | 
			
		||||
  * Decent use of `try { ... } catch(e) ...` and `promise.catch()`
 | 
			
		||||
    * the idea is that it shouldn't blow up at the slightest parse error without telling you which page is to blame (*cough* ruhoh *cough* jekyll)... bless me
 | 
			
		||||
  * Browser (optional)
 | 
			
		||||
    * using your front-end templates to build in your front-end? Imagine that!
 | 
			
		||||
  * io.js (node.js) (optional)
 | 
			
		||||
    * if you'd prefer to go headless, you can.
 | 
			
		||||
  * The server is *very* minimal and could easily be implemented in any language (such as ruby or python).
 | 
			
		||||
- `JavaScript` - it's so stable it takes 10 years to get new any features.
 | 
			
		||||
  - Won't break every time you upgrade OS X and reinstall `brew` (_cough_ ruby)
 | 
			
		||||
- Decent use of `try { ... } catch(e) ...` and `promise.catch()`
 | 
			
		||||
  - the idea is that it shouldn't blow up at the slightest parse error without telling you which page is to blame (_cough_ ruhoh _cough_ jekyll)... bless me
 | 
			
		||||
- Browser (optional)
 | 
			
		||||
  - using your front-end templates to build in your front-end? Imagine that!
 | 
			
		||||
- io.js (node.js) (optional)
 | 
			
		||||
  - if you'd prefer to go headless, you can.
 | 
			
		||||
- The server is _very_ minimal and could easily be implemented in any language (such as ruby or python).
 | 
			
		||||
 | 
			
		||||
Installation
 | 
			
		||||
============
 | 
			
		||||
# Installation
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
bower install --save desirae
 | 
			
		||||
@ -38,8 +35,7 @@ bower install --save desirae
 | 
			
		||||
npm install --save desirae
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Why
 | 
			
		||||
===
 | 
			
		||||
# Why
 | 
			
		||||
 | 
			
		||||
Because I hate ruby.
 | 
			
		||||
 | 
			
		||||
@ -51,14 +47,13 @@ more (last year I made dozens of gists and 0 blog posts) and I just couldn't get
 | 
			
		||||
versions and gems and whatnot... so I gave up and wrote my own (because I needed something
 | 
			
		||||
compatible with ruhoh).
 | 
			
		||||
 | 
			
		||||
Usage Overview
 | 
			
		||||
==============
 | 
			
		||||
# Usage Overview
 | 
			
		||||
 | 
			
		||||
### Before we get started
 | 
			
		||||
 | 
			
		||||
(disclaimers)
 | 
			
		||||
 | 
			
		||||
**Browser**: The default fs adapter will request the config files from `/api/fs/`. 
 | 
			
		||||
**Browser**: The default fs adapter will request the config files from `/api/fs/`.
 | 
			
		||||
 | 
			
		||||
**Node**: Remember that desirae is built browser-first, and optimized to reduce the number of round-trips
 | 
			
		||||
(in case someone actually desides to host a Desi service, y'know?), so... the node adapter is built with
 | 
			
		||||
@ -70,11 +65,10 @@ It's an artifact of this project being born out of the ashes of my
 | 
			
		||||
 | 
			
		||||
### Getting Started
 | 
			
		||||
 | 
			
		||||
First off you need to declare a state object that will be used in every *desirae* action.
 | 
			
		||||
First off you need to declare a state object that will be used in every _desirae_ action.
 | 
			
		||||
 | 
			
		||||
```javascript
 | 
			
		||||
var desi = {}
 | 
			
		||||
  ;
 | 
			
		||||
var desi = {};
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
After that you'll load any plugins you need.
 | 
			
		||||
@ -156,26 +150,24 @@ Desi.registerRenderer(
 | 
			
		||||
);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
And then you'll initialize Desirae with an *environment*.
 | 
			
		||||
And then you'll initialize Desirae with an _environment_.
 | 
			
		||||
 | 
			
		||||
```javascript
 | 
			
		||||
Desirae.init(
 | 
			
		||||
  desi
 | 
			
		||||
, { url:                'https://johndoe.exmaple.com/blog'
 | 
			
		||||
  , base_url:           'https://johndoe.exmaple.com'
 | 
			
		||||
  , base_path:          '/blog'
 | 
			
		||||
  , compiled_path:      'compiled_dev'
 | 
			
		||||
Desirae.init(desi, {
 | 
			
		||||
  url: "https://johndoe.exmaple.com/blog",
 | 
			
		||||
  base_url: "https://johndoe.exmaple.com",
 | 
			
		||||
  base_path: "/blog",
 | 
			
		||||
  compiled_path: "compiled_dev",
 | 
			
		||||
 | 
			
		||||
                        // default: continue when possible
 | 
			
		||||
  , onError:            function (e) {
 | 
			
		||||
                          return Promise.reject(e);
 | 
			
		||||
                        }
 | 
			
		||||
  // default: continue when possible
 | 
			
		||||
  onError: function (e) {
 | 
			
		||||
    return Promise.reject(e);
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
                        // io.js / node.js only
 | 
			
		||||
  , working_path:       './path/to/blog'
 | 
			
		||||
  }
 | 
			
		||||
).then(function () {
 | 
			
		||||
  console.log('Desirae is initialized');
 | 
			
		||||
  // io.js / node.js only
 | 
			
		||||
  working_path: "./path/to/blog",
 | 
			
		||||
}).then(function () {
 | 
			
		||||
  console.log("Desirae is initialized");
 | 
			
		||||
});
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
@ -198,43 +190,38 @@ Desirae.write(desi, env).then(function () {
 | 
			
		||||
});
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Plugins
 | 
			
		||||
 | 
			
		||||
You need to start every file with a wrapper that is browser and io.js/node.js compatible
 | 
			
		||||
 | 
			
		||||
```javascript
 | 
			
		||||
/*jshint -W054 */
 | 
			
		||||
;(function (exports) {
 | 
			
		||||
  'use strict';
 | 
			
		||||
 
 | 
			
		||||
  var DesiraeMyModule = {}
 | 
			
		||||
    ;
 | 
			
		||||
(function (exports) {
 | 
			
		||||
  "use strict";
 | 
			
		||||
 | 
			
		||||
  var DesiraeMyModule = {};
 | 
			
		||||
  // ... a bunch of code ...
 | 
			
		||||
 | 
			
		||||
  DesiraeMyModule.doStuff = doStuff;
 | 
			
		||||
 | 
			
		||||
  exports.DesiraeMyModule = DesiraeMyModule.DesiraeMyModule = DesiraeMyModule;
 | 
			
		||||
}('undefined' !== typeof exports && exports || window));
 | 
			
		||||
})(("undefined" !== typeof exports && exports) || window);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Other than that, just be mindful that your code needs to run in both iojs/node and browser environments
 | 
			
		||||
so steer away from things that are super iojs/node-ish or super window-ish.
 | 
			
		||||
 | 
			
		||||
Configuration
 | 
			
		||||
=============
 | 
			
		||||
# Configuration
 | 
			
		||||
 | 
			
		||||
There are a few configuration files:
 | 
			
		||||
 | 
			
		||||
* `site.yml` is stuff that might be unique to your site, such as (title, url, adwords id, etc)
 | 
			
		||||
* `authors/<<your-handle.yml>>` contains information about you (name, handle, facebook, etc)
 | 
			
		||||
* `config.yml` contains directives that describe *how* the blog should be compiled - more technical stuff.
 | 
			
		||||
- `site.yml` is stuff that might be unique to your site, such as (title, url, adwords id, etc)
 | 
			
		||||
- `authors/<<your-handle.yml>>` contains information about you (name, handle, facebook, etc)
 | 
			
		||||
- `config.yml` contains directives that describe _how_ the blog should be compiled - more technical stuff.
 | 
			
		||||
 | 
			
		||||
If any of these files change, the entire site needs to be retemplated.
 | 
			
		||||
 | 
			
		||||
API
 | 
			
		||||
===
 | 
			
		||||
# API
 | 
			
		||||
 | 
			
		||||
I'd like to make the plugin system connect-style API for adding plugins or whatever so that,
 | 
			
		||||
for example, so you could have a custom markdown preprocessor (that handles includes, perhaps)
 | 
			
		||||
@ -246,28 +233,26 @@ But here's what I've got so far:
 | 
			
		||||
 | 
			
		||||
### (html, markdown, jade)
 | 
			
		||||
 | 
			
		||||
* `Desirae.registerRenderer(ext, fn)`
 | 
			
		||||
- `Desirae.registerRenderer(ext, fn)`
 | 
			
		||||
 | 
			
		||||
For example, if you want to add the ability to render from `slim` or `haml`
 | 
			
		||||
instead of just `markdown` you could find the appropriate
 | 
			
		||||
JavaScript module (or make requests to an API service that renders them for you) and do this
 | 
			
		||||
 | 
			
		||||
```javascript
 | 
			
		||||
var slim = exports.slimjs || require('slimjs')
 | 
			
		||||
  ;
 | 
			
		||||
 | 
			
		||||
function render(contentstr/*, desi*/) {
 | 
			
		||||
var slim = exports.slimjs || require("slimjs");
 | 
			
		||||
function render(contentstr /*, desi*/) {
 | 
			
		||||
  return PromiseA.resolve(slim(contentstr));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Desirae.registerRenderer('.slim', render);
 | 
			
		||||
Desirae.registerRenderer(".slim", render);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Data Mapping
 | 
			
		||||
 | 
			
		||||
### (desirae, ruhoh, etc)
 | 
			
		||||
 | 
			
		||||
* `Desirae.registerDataMapper(ext, fn)`
 | 
			
		||||
- `Desirae.registerDataMapper(ext, fn)`
 | 
			
		||||
 | 
			
		||||
If you want to use a non-desirae theme that uses attributes in a different than
 | 
			
		||||
how Desirae creates the view object internally
 | 
			
		||||
@ -276,18 +261,18 @@ data mapper to accomplish this.
 | 
			
		||||
 | 
			
		||||
Please try not to modify the original object if you can avoid it.
 | 
			
		||||
 | 
			
		||||
*TODO: maybe pass in a two-level deep shallow copy ?*
 | 
			
		||||
_TODO: maybe pass in a two-level deep shallow copy ?_
 | 
			
		||||
 | 
			
		||||
```javascript
 | 
			
		||||
Desirae.registerDataMapper('ruhoh@3.0', function (view) {
 | 
			
		||||
Desirae.registerDataMapper("ruhoh@3.0", function (view) {
 | 
			
		||||
  return {
 | 
			
		||||
    page: {
 | 
			
		||||
      name: view.entity.title
 | 
			
		||||
    }
 | 
			
		||||
  , author: {
 | 
			
		||||
      nickname: view.author.twitter
 | 
			
		||||
    }
 | 
			
		||||
    // ... 
 | 
			
		||||
      name: view.entity.title,
 | 
			
		||||
    },
 | 
			
		||||
    author: {
 | 
			
		||||
      nickname: view.author.twitter,
 | 
			
		||||
    },
 | 
			
		||||
    // ...
 | 
			
		||||
  };
 | 
			
		||||
});
 | 
			
		||||
```
 | 
			
		||||
@ -305,54 +290,54 @@ I'd love to work with anyone who is familiar with the Dropbox or similar APIs.
 | 
			
		||||
 | 
			
		||||
I think it would be awesome to support various means of storage. Perhaps github gists too.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Server
 | 
			
		||||
======
 | 
			
		||||
# Server
 | 
			
		||||
 | 
			
		||||
Obviously there has to be a server with some sort of storage and retrieval mechanism.
 | 
			
		||||
 | 
			
		||||
I've implemented a very simple node server using the filesystem.
 | 
			
		||||
 | 
			
		||||
GET /api/fs/walk
 | 
			
		||||
------------
 | 
			
		||||
## GET /api/fs/walk
 | 
			
		||||
 | 
			
		||||
`GET http://local.dear.desi:8080/api/fs/walk?dir=posts&dotfiles=true&extensions=md,markdown,jade,htm,html`
 | 
			
		||||
 | 
			
		||||
* `dir` **must** be supplied. returns a flat list of all files, recursively
 | 
			
		||||
* `dotfiles` default to `false`. includes dotfiles when `true`.
 | 
			
		||||
* `extensions` defaults to `null`. inclode **only** the supplied extensions when `true`.
 | 
			
		||||
- `dir` **must** be supplied. returns a flat list of all files, recursively
 | 
			
		||||
- `dotfiles` default to `false`. includes dotfiles when `true`.
 | 
			
		||||
- `extensions` defaults to `null`. inclode **only** the supplied extensions when `true`.
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
[
 | 
			
		||||
  { "name": "happy-new-year.md"
 | 
			
		||||
  , "createdDate": "2015-01-05T18:19:30.000Z"
 | 
			
		||||
  , "lastModifiedDate": "2015-01-05T18:19:30.000Z"
 | 
			
		||||
  , "size": 2121
 | 
			
		||||
  , "relativePath": "posts/2015"
 | 
			
		||||
  }
 | 
			
		||||
  {
 | 
			
		||||
    "name": "happy-new-year.md",
 | 
			
		||||
    "createdDate": "2015-01-05T18:19:30.000Z",
 | 
			
		||||
    "lastModifiedDate": "2015-01-05T18:19:30.000Z",
 | 
			
		||||
    "size": 2121,
 | 
			
		||||
    "relativePath": "posts/2015"
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
, { "name": "tips-for-the-ages.jade"
 | 
			
		||||
  , "createdDate": "2014-06-16T18:19:30.000Z"
 | 
			
		||||
  , "lastModifiedDate": "2014-06-16T18:19:30.000Z"
 | 
			
		||||
  , "size": 389
 | 
			
		||||
  , "relativePath": "posts"
 | 
			
		||||
  }
 | 
			
		||||
, { "name": "my-first-post.html"
 | 
			
		||||
  , "createdDate": "2013-08-01T22:47:37.000Z"
 | 
			
		||||
  , "lastModifiedDate": "2013-08-01T22:47:37.000Z"
 | 
			
		||||
  , "size": 4118
 | 
			
		||||
  , "relativePath": "posts/2013"
 | 
			
		||||
  {
 | 
			
		||||
    "name": "tips-for-the-ages.jade",
 | 
			
		||||
    "createdDate": "2014-06-16T18:19:30.000Z",
 | 
			
		||||
    "lastModifiedDate": "2014-06-16T18:19:30.000Z",
 | 
			
		||||
    "size": 389,
 | 
			
		||||
    "relativePath": "posts"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "my-first-post.html",
 | 
			
		||||
    "createdDate": "2013-08-01T22:47:37.000Z",
 | 
			
		||||
    "lastModifiedDate": "2013-08-01T22:47:37.000Z",
 | 
			
		||||
    "size": 4118,
 | 
			
		||||
    "relativePath": "posts/2013"
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
To retrieve multiple dir listings at once:
 | 
			
		||||
 | 
			
		||||
* for a few simple dirs without special chars just change `dir` to `dirs` and separate with commas
 | 
			
		||||
- for a few simple dirs without special chars just change `dir` to `dirs` and separate with commas
 | 
			
		||||
 | 
			
		||||
`GET http://local.dear.desi:8080/api/fs/walk?dirs=posts/2015,posts/2013&dotfiles=true&extensions=md,markdown,jade,htm,html`
 | 
			
		||||
 | 
			
		||||
* for many dirs, or dirs with special chars, `POST` an object containing an array of `dirs` with  `&_method=GET` appended to the url.
 | 
			
		||||
- for many dirs, or dirs with special chars, `POST` an object containing an array of `dirs` with `&_method=GET` appended to the url.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
POST http://local.dear.desi:8080/api/fs/walk?dotfiles=true&extensions=md,markdown,jade,htm,html&_method=GET
 | 
			
		||||
@ -367,27 +352,27 @@ POST http://local.dear.desi:8080/api/fs/walk?dotfiles=true&extensions=md,markdow
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
GET /api/fs/files
 | 
			
		||||
-------------
 | 
			
		||||
## GET /api/fs/files
 | 
			
		||||
 | 
			
		||||
`GET http://local.dear.desi:8080/api/fs/files?path=posts/happy-new-year.md`
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{ "path": "posts/intro-to-http-with-netcat-node-connect.md"
 | 
			
		||||
, "createdDate": "2013-08-01T22:47:37.000Z"
 | 
			
		||||
, "lastModifiedDate": "2013-08-01T22:47:37.000Z"
 | 
			
		||||
, "contents": "..."
 | 
			
		||||
, "sha1": "6eae3a5b062c6d0d79f070c26e6d62486b40cb46"
 | 
			
		||||
{
 | 
			
		||||
  "path": "posts/intro-to-http-with-netcat-node-connect.md",
 | 
			
		||||
  "createdDate": "2013-08-01T22:47:37.000Z",
 | 
			
		||||
  "lastModifiedDate": "2013-08-01T22:47:37.000Z",
 | 
			
		||||
  "contents": "...",
 | 
			
		||||
  "sha1": "6eae3a5b062c6d0d79f070c26e6d62486b40cb46"
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
To retrieve multiple files at once:
 | 
			
		||||
 | 
			
		||||
* for a few simple files without special chars just change `path` to `paths` and separate with commas
 | 
			
		||||
- for a few simple files without special chars just change `path` to `paths` and separate with commas
 | 
			
		||||
 | 
			
		||||
`GET http://local.dear.desi:8080/api/fs/files?paths=posts/foo.md,posts/bar.md`
 | 
			
		||||
 | 
			
		||||
* for many files, or files with special chars, `POST` an object containing an array of `pathss` with  `&_method=GET` appended to the url.
 | 
			
		||||
- for many files, or files with special chars, `POST` an object containing an array of `pathss` with `&_method=GET` appended to the url.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
POST http://local.dear.desi:8080/api/fs/files?dotfiles=true&extensions=md,markdown,jade,htm,html&_method=GET
 | 
			
		||||
@ -406,8 +391,7 @@ POST http://local.dear.desi:8080/api/fs/files?dotfiles=true&extensions=md,markdo
 | 
			
		||||
]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
POST /api/fs/files
 | 
			
		||||
------------------
 | 
			
		||||
## POST /api/fs/files
 | 
			
		||||
 | 
			
		||||
By default this should assume that you intended to write to the compiled directory
 | 
			
		||||
and return an error if you try to write to any other directory, unless `compiled=false` (not yet implemented).
 | 
			
		||||
@ -452,9 +436,8 @@ The response may include errors of all shapes and sizes.
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
POST /api/fs/copy
 | 
			
		||||
------------------
 | 
			
		||||
## POST /api/fs/copy
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{ files: { "assets/logo.png": "compiled/assets/logo.png" } }
 | 
			
		||||
{ "files": { "assets/logo.png": "compiled/assets/logo.png" } }
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										46
									
								
								TODO.md
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								TODO.md
									
									
									
									
									
								
							@ -4,7 +4,6 @@ show file path
 | 
			
		||||
show prod url
 | 
			
		||||
show dev url
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
POST tests
 | 
			
		||||
create a title and delete it (no error)
 | 
			
		||||
change the format. does the permalink change? (yes)
 | 
			
		||||
@ -16,22 +15,17 @@ change the format in the frontmatter permalink. does the format change? (yes)
 | 
			
		||||
create a description and delete it (no error)
 | 
			
		||||
create a description. does the frontmatter change? (yes)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
protection
 | 
			
		||||
Don't allow changing the uuid, original_url, or original_date
 | 
			
		||||
 | 
			
		||||
TODO
 | 
			
		||||
---
 | 
			
		||||
## TODO
 | 
			
		||||
 | 
			
		||||
check that no other post uses the same permalink
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
default data-model 'ruhoh@2.2'
 | 
			
		||||
other data-model 'desirae@1.0'
 | 
			
		||||
 | 
			
		||||
Widgets
 | 
			
		||||
=======
 | 
			
		||||
# Widgets
 | 
			
		||||
 | 
			
		||||
All widgets should export an object with a `create(widgetConf, desiState)` function that returns a promise.
 | 
			
		||||
 | 
			
		||||
@ -42,7 +36,7 @@ widgets:
 | 
			
		||||
    # stuff like google ad and disqus ids should go in config.yml or data.yml
 | 
			
		||||
    config:
 | 
			
		||||
      foobeep: boop
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
    handle:
 | 
			
		||||
      - html
 | 
			
		||||
      - markdown
 | 
			
		||||
@ -52,11 +46,10 @@ widgets:
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```javascript
 | 
			
		||||
'use strict';
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
module.exports.Foogizmo.create = function (foogizmoConf, desiState) {
 | 
			
		||||
  return new Promise(function (resolve) {
 | 
			
		||||
 | 
			
		||||
    function pager(desiPageState) {
 | 
			
		||||
      // Do processing
 | 
			
		||||
 | 
			
		||||
@ -68,29 +61,28 @@ module.exports.Foogizmo.create = function (foogizmoConf, desiState) {
 | 
			
		||||
 | 
			
		||||
      desiPostState.fooembedinator = function (fooval) {
 | 
			
		||||
        // figure out what type of link fooval is and return iframe html
 | 
			
		||||
        return '<iframe src="http://embedinator.com/"' + foovalProcessed + '></iframe>'
 | 
			
		||||
      }
 | 
			
		||||
        return (
 | 
			
		||||
          '<iframe src="http://embedinator.com/"' +
 | 
			
		||||
          foovalProcessed +
 | 
			
		||||
          "></iframe>"
 | 
			
		||||
        );
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    resolve({ foopager: pager, fooposter: poster });
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Overlays
 | 
			
		||||
--------
 | 
			
		||||
## Overlays
 | 
			
		||||
 | 
			
		||||
For any config a widget uses, it should also check on post.fooconfig and theme.fooconfig to make sure that they don't override the foogizmo.config.fooconfig
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Migrating from Ruhoh
 | 
			
		||||
====================
 | 
			
		||||
# Migrating from Ruhoh
 | 
			
		||||
 | 
			
		||||
There are only a few things in Ruhoh that could only be done in ruby or were otherwise difficult to work around.
 | 
			
		||||
 | 
			
		||||
config.yml
 | 
			
		||||
----------
 | 
			
		||||
## config.yml
 | 
			
		||||
 | 
			
		||||
Instead of having special names for some properties (`_root`)
 | 
			
		||||
and `use` sub attributes for others (`twitter` theme, posts directory),
 | 
			
		||||
@ -117,19 +109,15 @@ widgets [NO CHANGE]
 | 
			
		||||
 | 
			
		||||
All directories are ignored by default. If you want a directory to be interpreted as a collection of pages you need to specify it in the `collections` hash.
 | 
			
		||||
 | 
			
		||||
data.yml
 | 
			
		||||
--------
 | 
			
		||||
## data.yml
 | 
			
		||||
 | 
			
		||||
No changes
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
config.ru
 | 
			
		||||
---------
 | 
			
		||||
## config.ru
 | 
			
		||||
 | 
			
		||||
REMOVED (ruby only)
 | 
			
		||||
 | 
			
		||||
themes layout
 | 
			
		||||
-------------
 | 
			
		||||
## themes layout
 | 
			
		||||
 | 
			
		||||
TODO
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										17
									
								
								bower.json
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								bower.json
									
									
									
									
									
								
							@ -1,15 +1,10 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "desirae",
 | 
			
		||||
  "version": "0.11.2",
 | 
			
		||||
  "authors": [
 | 
			
		||||
    "AJ ONeal <awesome@coolaj86.com>"
 | 
			
		||||
  ],
 | 
			
		||||
  "authors": ["AJ ONeal <awesome@coolaj86.com>"],
 | 
			
		||||
  "description": "A blogging platform in the browser. Wow!",
 | 
			
		||||
  "main": "desirae.js",
 | 
			
		||||
  "moduleType": [
 | 
			
		||||
    "globals",
 | 
			
		||||
    "node"
 | 
			
		||||
  ],
 | 
			
		||||
  "moduleType": ["globals", "node"],
 | 
			
		||||
  "keywords": [
 | 
			
		||||
    "desirae",
 | 
			
		||||
    "dear",
 | 
			
		||||
@ -26,13 +21,7 @@
 | 
			
		||||
  ],
 | 
			
		||||
  "license": "Apache2",
 | 
			
		||||
  "homepage": "http://github.com/DearDesi/desirae",
 | 
			
		||||
  "ignore": [
 | 
			
		||||
    "**/.*",
 | 
			
		||||
    "node_modules",
 | 
			
		||||
    "bower_components",
 | 
			
		||||
    "test",
 | 
			
		||||
    "tests"
 | 
			
		||||
  ],
 | 
			
		||||
  "ignore": ["**/.*", "node_modules", "bower_components", "test", "tests"],
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "bluebird": "~2.6.2",
 | 
			
		||||
    "escape-string-regexp": "~1.0.2",
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1091
									
								
								desirae.js
									
									
									
									
									
								
							
							
						
						
									
										1091
									
								
								desirae.js
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -1,25 +1,23 @@
 | 
			
		||||
/*jshint -W054 */
 | 
			
		||||
;(function (exports) {
 | 
			
		||||
  'use strict';
 | 
			
		||||
 | 
			
		||||
  var path = exports.path || require('path')
 | 
			
		||||
    , months
 | 
			
		||||
    , cores = {}
 | 
			
		||||
    ;
 | 
			
		||||
(function (exports) {
 | 
			
		||||
  "use strict";
 | 
			
		||||
 | 
			
		||||
  var path = exports.path || require("path"),
 | 
			
		||||
    months,
 | 
			
		||||
    cores = {};
 | 
			
		||||
  months = {
 | 
			
		||||
    1: 'January'
 | 
			
		||||
  , 2: 'February'
 | 
			
		||||
  , 3: 'March'
 | 
			
		||||
  , 4: 'April'
 | 
			
		||||
  , 5: 'May'
 | 
			
		||||
  , 6: 'June'
 | 
			
		||||
  , 7: 'July'
 | 
			
		||||
  , 8: 'August'
 | 
			
		||||
  , 9: 'September'
 | 
			
		||||
  , 10: 'October'
 | 
			
		||||
  , 11: 'November'
 | 
			
		||||
  , 12: 'December'
 | 
			
		||||
    1: "January",
 | 
			
		||||
    2: "February",
 | 
			
		||||
    3: "March",
 | 
			
		||||
    4: "April",
 | 
			
		||||
    5: "May",
 | 
			
		||||
    6: "June",
 | 
			
		||||
    7: "July",
 | 
			
		||||
    8: "August",
 | 
			
		||||
    9: "September",
 | 
			
		||||
    10: "October",
 | 
			
		||||
    11: "November",
 | 
			
		||||
    12: "December",
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  function byDate(a, b) {
 | 
			
		||||
@ -67,9 +65,7 @@
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function collate(entities, env) {
 | 
			
		||||
    var yearsArr = []
 | 
			
		||||
      ;
 | 
			
		||||
 | 
			
		||||
    var yearsArr = [];
 | 
			
		||||
    entities.forEach(function (f) {
 | 
			
		||||
      var set;
 | 
			
		||||
      var yindex = 3000 - f.year;
 | 
			
		||||
@ -85,10 +81,10 @@
 | 
			
		||||
 | 
			
		||||
      if (!set.months[mindex]) {
 | 
			
		||||
        set.months[mindex] = {
 | 
			
		||||
          month_name: monthName
 | 
			
		||||
        , month_number: mindex
 | 
			
		||||
        , month: monthName
 | 
			
		||||
        , pages: []
 | 
			
		||||
          month_name: monthName,
 | 
			
		||||
          month_number: mindex,
 | 
			
		||||
          month: monthName,
 | 
			
		||||
          pages: [],
 | 
			
		||||
        };
 | 
			
		||||
      }
 | 
			
		||||
      set = set.months[mindex];
 | 
			
		||||
@ -125,4 +121,4 @@
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  exports.DesiraeAggregateCore = cores.DesiraeAggregateCore = cores;
 | 
			
		||||
}('undefined' !== typeof exports && exports || window));
 | 
			
		||||
})(("undefined" !== typeof exports && exports) || window);
 | 
			
		||||
 | 
			
		||||
@ -1,67 +1,66 @@
 | 
			
		||||
/*jshint -W054 */
 | 
			
		||||
;(function (exports) {
 | 
			
		||||
  'use strict';
 | 
			
		||||
(function (exports) {
 | 
			
		||||
  "use strict";
 | 
			
		||||
 | 
			
		||||
  function create(Desi) {
 | 
			
		||||
    // Chrome, Firefox, and even MSIE11+ all support crypto
 | 
			
		||||
    var crypto = window.crypto || window.msCrypto
 | 
			
		||||
      , PromiseA = window.Promise
 | 
			
		||||
      , algos
 | 
			
		||||
      ;
 | 
			
		||||
    var crypto = window.crypto || window.msCrypto,
 | 
			
		||||
      PromiseA = window.Promise,
 | 
			
		||||
      algos;
 | 
			
		||||
 | 
			
		||||
    // convenience mappings for common digest algorithms
 | 
			
		||||
    algos = {
 | 
			
		||||
      'sha1': 'SHA-1'
 | 
			
		||||
    , 'sha256': 'SHA-256'
 | 
			
		||||
    , 'sha512': 'SHA-512'
 | 
			
		||||
      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);
 | 
			
		||||
      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) {
 | 
			
		||||
      // 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;
 | 
			
		||||
      });
 | 
			
		||||
      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
 | 
			
		||||
        ;
 | 
			
		||||
      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;
 | 
			
		||||
          c = "0" + c;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        hex += c;
 | 
			
		||||
@ -72,36 +71,31 @@
 | 
			
		||||
 | 
			
		||||
    // convert from string to arraybuffer
 | 
			
		||||
    function str2ab(stringToEncode, insertBom) {
 | 
			
		||||
      stringToEncode = stringToEncode.replace(/\r\n/g,"\n");
 | 
			
		||||
      stringToEncode = stringToEncode.replace(/\r\n/g, "\n");
 | 
			
		||||
 | 
			
		||||
      var utftext = []
 | 
			
		||||
        , n
 | 
			
		||||
        , c
 | 
			
		||||
        ;
 | 
			
		||||
      var utftext = [],
 | 
			
		||||
        n,
 | 
			
		||||
        c;
 | 
			
		||||
 | 
			
		||||
      if (true === insertBom)  {
 | 
			
		||||
        utftext[0] =  0xef;
 | 
			
		||||
        utftext[1] =  0xbb;
 | 
			
		||||
        utftext[2] =  0xbf;
 | 
			
		||||
      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;
 | 
			
		||||
          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;
 | 
			
		||||
        }
 | 
			
		||||
        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;
 | 
			
		||||
    }
 | 
			
		||||
@ -112,26 +106,21 @@
 | 
			
		||||
    //
 | 
			
		||||
    // FSAPI
 | 
			
		||||
    //
 | 
			
		||||
    var fsapi
 | 
			
		||||
      ;
 | 
			
		||||
    var fsapi;
 | 
			
		||||
 | 
			
		||||
    function request() {
 | 
			
		||||
    }
 | 
			
		||||
    request.get = function (url/*, query*/) {
 | 
			
		||||
    function request() {}
 | 
			
		||||
    request.get = function (url /*, query*/) {
 | 
			
		||||
      // Return a new promise.
 | 
			
		||||
      return new PromiseA(function(resolve, reject) {
 | 
			
		||||
      return new PromiseA(function (resolve, reject) {
 | 
			
		||||
        // Do the usual XHR stuff
 | 
			
		||||
        var req = new XMLHttpRequest()
 | 
			
		||||
          ;
 | 
			
		||||
 | 
			
		||||
        req.onload = function() {
 | 
			
		||||
        var req = new XMLHttpRequest();
 | 
			
		||||
        req.onload = function () {
 | 
			
		||||
          // This is called even on 404 etc
 | 
			
		||||
          // so check the status
 | 
			
		||||
          if (200 === req.status) {
 | 
			
		||||
            // Resolve the promise with the response text
 | 
			
		||||
            resolve(req.response);
 | 
			
		||||
          }
 | 
			
		||||
          else {
 | 
			
		||||
          } else {
 | 
			
		||||
            // Otherwise reject with the status text
 | 
			
		||||
            // which will hopefully be a meaningful error
 | 
			
		||||
            reject(Error(req.statusText));
 | 
			
		||||
@ -139,30 +128,27 @@
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Handle network errors
 | 
			
		||||
        req.onerror = function() {
 | 
			
		||||
        req.onerror = function () {
 | 
			
		||||
          reject(Error("Network Error"));
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Make the request
 | 
			
		||||
        req.open('GET', url);
 | 
			
		||||
        req.open("GET", url);
 | 
			
		||||
        req.send();
 | 
			
		||||
      });
 | 
			
		||||
    };
 | 
			
		||||
    request.post = function (url/*, query*/, body) {
 | 
			
		||||
    request.post = function (url /*, query*/, body) {
 | 
			
		||||
      // Return a new promise.
 | 
			
		||||
      return new PromiseA(function(resolve, reject) {
 | 
			
		||||
      return new PromiseA(function (resolve, reject) {
 | 
			
		||||
        // Do the usual XHR stuff
 | 
			
		||||
        var req = new XMLHttpRequest()
 | 
			
		||||
          ;
 | 
			
		||||
 | 
			
		||||
        req.onload = function() {
 | 
			
		||||
        var req = new XMLHttpRequest();
 | 
			
		||||
        req.onload = function () {
 | 
			
		||||
          // This is called even on 404 etc
 | 
			
		||||
          // so check the status
 | 
			
		||||
          if (200 === req.status) {
 | 
			
		||||
            // Resolve the promise with the response text
 | 
			
		||||
            resolve(req.response);
 | 
			
		||||
          }
 | 
			
		||||
          else {
 | 
			
		||||
          } else {
 | 
			
		||||
            // Otherwise reject with the status text
 | 
			
		||||
            // which will hopefully be a meaningful error
 | 
			
		||||
            reject(Error(req.statusText));
 | 
			
		||||
@ -170,14 +156,14 @@
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Handle network errors
 | 
			
		||||
        req.onerror = function() {
 | 
			
		||||
        req.onerror = function () {
 | 
			
		||||
          reject(Error("Network Error"));
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        req.open('POST', url);
 | 
			
		||||
        req.open("POST", url);
 | 
			
		||||
        req.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
 | 
			
		||||
        // Make the request
 | 
			
		||||
        if ('string' !== typeof body) {
 | 
			
		||||
        if ("string" !== typeof body) {
 | 
			
		||||
          body = JSON.stringify(body);
 | 
			
		||||
        }
 | 
			
		||||
        req.send(body);
 | 
			
		||||
@ -188,87 +174,93 @@
 | 
			
		||||
    fsapi.getMeta = function (collections, opts) {
 | 
			
		||||
      opts = opts || {};
 | 
			
		||||
 | 
			
		||||
      var extensions = ''
 | 
			
		||||
        , dotfiles = ''
 | 
			
		||||
        , contents = ''
 | 
			
		||||
        , sha1sum = ''
 | 
			
		||||
        ;
 | 
			
		||||
 | 
			
		||||
      var extensions = "",
 | 
			
		||||
        dotfiles = "",
 | 
			
		||||
        contents = "",
 | 
			
		||||
        sha1sum = "";
 | 
			
		||||
      if (Array.isArray(opts.extensions)) {
 | 
			
		||||
        extensions = '&extensions=' + opts.extensions.join(','); // md,markdown,jade,htm,html
 | 
			
		||||
        extensions = "&extensions=" + opts.extensions.join(","); // md,markdown,jade,htm,html
 | 
			
		||||
      }
 | 
			
		||||
      if (opts.dotfiles) {
 | 
			
		||||
        dotfiles = '&dotfiles=true';
 | 
			
		||||
        dotfiles = "&dotfiles=true";
 | 
			
		||||
      }
 | 
			
		||||
      if (opts.contents) {
 | 
			
		||||
        contents = '&contents=true';
 | 
			
		||||
        contents = "&contents=true";
 | 
			
		||||
      }
 | 
			
		||||
      if (false === opts.sha1sum) {
 | 
			
		||||
        sha1sum = '&sha1sum=false';
 | 
			
		||||
        sha1sum = "&sha1sum=false";
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return request.post('/api/fs/walk?_method=GET' + dotfiles + extensions + contents + sha1sum, {
 | 
			
		||||
        dirs: collections
 | 
			
		||||
      }).then(function (resp) {
 | 
			
		||||
        return JSON.parse(resp);
 | 
			
		||||
      }).catch(function (e) {
 | 
			
		||||
        throw e;
 | 
			
		||||
      });
 | 
			
		||||
      return request
 | 
			
		||||
        .post(
 | 
			
		||||
          "/api/fs/walk?_method=GET" +
 | 
			
		||||
            dotfiles +
 | 
			
		||||
            extensions +
 | 
			
		||||
            contents +
 | 
			
		||||
            sha1sum,
 | 
			
		||||
          {
 | 
			
		||||
            dirs: collections,
 | 
			
		||||
          }
 | 
			
		||||
        )
 | 
			
		||||
        .then(function (resp) {
 | 
			
		||||
          return JSON.parse(resp);
 | 
			
		||||
        })
 | 
			
		||||
        .catch(function (e) {
 | 
			
		||||
          throw e;
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    fsapi.getContents = function (filepaths) {
 | 
			
		||||
      return request.post('/api/fs/files?_method=GET', {
 | 
			
		||||
        paths: filepaths
 | 
			
		||||
      }).then(function (resp) {
 | 
			
		||||
        return JSON.parse(resp);
 | 
			
		||||
      });
 | 
			
		||||
      return request
 | 
			
		||||
        .post("/api/fs/files?_method=GET", {
 | 
			
		||||
          paths: filepaths,
 | 
			
		||||
        })
 | 
			
		||||
        .then(function (resp) {
 | 
			
		||||
          return JSON.parse(resp);
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    fsapi.getCache = function () {
 | 
			
		||||
      return request.get('/api/fs/static/cache.json').then(function (resp) {
 | 
			
		||||
        return JSON.parse(resp);
 | 
			
		||||
      }).catch(function (/*e*/) {
 | 
			
		||||
        return {};
 | 
			
		||||
      }).then(function (obj) {
 | 
			
		||||
        return obj;
 | 
			
		||||
      });
 | 
			
		||||
      return request
 | 
			
		||||
        .get("/api/fs/static/cache.json")
 | 
			
		||||
        .then(function (resp) {
 | 
			
		||||
          return JSON.parse(resp);
 | 
			
		||||
        })
 | 
			
		||||
        .catch(function (/*e*/) {
 | 
			
		||||
          return {};
 | 
			
		||||
        })
 | 
			
		||||
        .then(function (obj) {
 | 
			
		||||
          return obj;
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    fsapi.copy = function (files) {
 | 
			
		||||
      var body = { files: files };
 | 
			
		||||
      body = JSON.stringify(body); // this is more or less instant for a few MiB of posts
 | 
			
		||||
      return request.post('/api/fs/copy', body).then(function (resp) {
 | 
			
		||||
        var response = JSON.parse(resp)
 | 
			
		||||
          ;
 | 
			
		||||
 | 
			
		||||
      return request.post("/api/fs/copy", body).then(function (resp) {
 | 
			
		||||
        var response = JSON.parse(resp);
 | 
			
		||||
        // not accurate for utf8/unicode, but close enough
 | 
			
		||||
        response.size = body.length;
 | 
			
		||||
        return response;
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    fsapi.putFiles = function (files) {
 | 
			
		||||
      var body = { files: files }
 | 
			
		||||
        ;
 | 
			
		||||
 | 
			
		||||
      var body = { files: files };
 | 
			
		||||
      files.forEach(function (file) {
 | 
			
		||||
        if (!file.contents || 'string' === typeof file.contents) {
 | 
			
		||||
        if (!file.contents || "string" === typeof file.contents) {
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
        if (/\.json$/i.test(file.path)) {
 | 
			
		||||
          file.contents = JSON.stringify(file.contents);
 | 
			
		||||
        }
 | 
			
		||||
        else if (/\.ya?ml$/i.test(file.path)) {
 | 
			
		||||
          file.contents = exports.jsyaml.dump(file.contents); 
 | 
			
		||||
        } else if (/\.ya?ml$/i.test(file.path)) {
 | 
			
		||||
          file.contents = exports.jsyaml.dump(file.contents);
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      body = JSON.stringify(body); // this is more or less instant for a few MiB of posts
 | 
			
		||||
      return request.post('/api/fs/files', body).then(function (resp) {
 | 
			
		||||
        var response = JSON.parse(resp)
 | 
			
		||||
          ;
 | 
			
		||||
 | 
			
		||||
      return request.post("/api/fs/files", body).then(function (resp) {
 | 
			
		||||
        var response = JSON.parse(resp);
 | 
			
		||||
        // not accurate for utf8/unicode, but close enough
 | 
			
		||||
        response.size = body.length;
 | 
			
		||||
        return response;
 | 
			
		||||
@ -281,4 +273,4 @@
 | 
			
		||||
  } else {
 | 
			
		||||
    exports.create = create;
 | 
			
		||||
  }
 | 
			
		||||
}('undefined' !== typeof exports && exports || window));
 | 
			
		||||
})(("undefined" !== typeof exports && exports) || window);
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,9 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
"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(
 | 
			
		||||
    "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.');
 | 
			
		||||
  throw new Error("Not Implemented.");
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
/*jshint -W054 */
 | 
			
		||||
;(function (exports) {
 | 
			
		||||
  'use strict';
 | 
			
		||||
(function (exports) {
 | 
			
		||||
  "use strict";
 | 
			
		||||
 | 
			
		||||
  function desiMap(obj) {
 | 
			
		||||
    obj.desi = obj;
 | 
			
		||||
@ -8,4 +8,4 @@
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  exports.DesiraeDatamapCore = desiMap.DesiraeDatamapCore = desiMap;
 | 
			
		||||
}('undefined' !== typeof exports && exports || window));
 | 
			
		||||
})(("undefined" !== typeof exports && exports) || window);
 | 
			
		||||
 | 
			
		||||
@ -1,19 +1,17 @@
 | 
			
		||||
/*jshint -W054 */
 | 
			
		||||
;(function (exports) {
 | 
			
		||||
  'use strict';
 | 
			
		||||
(function (exports) {
 | 
			
		||||
  "use strict";
 | 
			
		||||
 | 
			
		||||
  function create(Desi) {
 | 
			
		||||
    Desi.YAML           = {};
 | 
			
		||||
    Desi.YAML.parse     = (exports.jsyaml || require('js-yaml')).load;
 | 
			
		||||
    Desi.YAML.stringify = (exports.jsyaml || require('js-yaml')).dump;
 | 
			
		||||
    Desi.YAML = {};
 | 
			
		||||
    Desi.YAML.parse = (exports.jsyaml || require("js-yaml")).load;
 | 
			
		||||
    Desi.YAML.stringify = (exports.jsyaml || require("js-yaml")).dump;
 | 
			
		||||
 | 
			
		||||
    function readFrontMatter(text) {
 | 
			
		||||
      var lines
 | 
			
		||||
        , line
 | 
			
		||||
        , padIndent = ''
 | 
			
		||||
        , ymllines = []
 | 
			
		||||
        ;
 | 
			
		||||
 | 
			
		||||
      var lines,
 | 
			
		||||
        line,
 | 
			
		||||
        padIndent = "",
 | 
			
		||||
        ymllines = [];
 | 
			
		||||
      lines = text.split(/\n/);
 | 
			
		||||
      line = lines.shift();
 | 
			
		||||
 | 
			
		||||
@ -25,14 +23,14 @@
 | 
			
		||||
      // that start without indentation, so
 | 
			
		||||
      // we can add it if this is the case
 | 
			
		||||
      if (lines[0] && lines[0].match(/^\S/)) {
 | 
			
		||||
        padIndent = '';
 | 
			
		||||
        padIndent = "";
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      while (true) {
 | 
			
		||||
        line = lines.shift();
 | 
			
		||||
 | 
			
		||||
        // premature end-of-file (unsupported yaml)
 | 
			
		||||
        if (!line && '' !== line) {
 | 
			
		||||
        if (!line && "" !== line) {
 | 
			
		||||
          ymllines = [];
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
@ -44,24 +42,21 @@
 | 
			
		||||
 | 
			
		||||
        if (line) {
 | 
			
		||||
          // supported yaml
 | 
			
		||||
          ymllines.push(padIndent + line); 
 | 
			
		||||
          ymllines.push(padIndent + line);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
      // XXX can't be sorted because arrays get messed up
 | 
			
		||||
      //ymllines.sort();
 | 
			
		||||
      if (ymllines) {
 | 
			
		||||
        return '---\n' + ymllines.join('\n');
 | 
			
		||||
        return "---\n" + ymllines.join("\n");
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function separateText(text, fm) {
 | 
			
		||||
      var len
 | 
			
		||||
        , yml
 | 
			
		||||
        ;
 | 
			
		||||
      var len, yml;
 | 
			
		||||
 | 
			
		||||
      yml = readFrontMatter(fm);
 | 
			
		||||
      // strip frontmatter from text, if any
 | 
			
		||||
@ -72,27 +67,26 @@
 | 
			
		||||
        len = 0;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return text.split(/\n/).slice(len).join('\n');
 | 
			
		||||
      return text.split(/\n/).slice(len).join("\n");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function parseText(text) {
 | 
			
		||||
      var fm = readFrontMatter(text)
 | 
			
		||||
        , body = fm && separateText(text, fm)
 | 
			
		||||
        , yml
 | 
			
		||||
        ;
 | 
			
		||||
      var fm = readFrontMatter(text),
 | 
			
		||||
        body = fm && separateText(text, fm),
 | 
			
		||||
        yml;
 | 
			
		||||
 | 
			
		||||
      if (fm) {
 | 
			
		||||
        try {
 | 
			
		||||
          yml = Desi.YAML.parse(fm);
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
          //
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return {
 | 
			
		||||
        yml: yml
 | 
			
		||||
      , frontmatter: fm
 | 
			
		||||
      , body: body
 | 
			
		||||
        yml: yml,
 | 
			
		||||
        frontmatter: fm,
 | 
			
		||||
        body: body,
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -112,4 +106,4 @@
 | 
			
		||||
  } else {
 | 
			
		||||
    exports.create = create;
 | 
			
		||||
  }
 | 
			
		||||
}('undefined' !== typeof exports && exports || window));
 | 
			
		||||
})(("undefined" !== typeof exports && exports) || window);
 | 
			
		||||
 | 
			
		||||
@ -1,51 +1,47 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
var PromiseA = require('bluebird').Promise
 | 
			
		||||
  , fs = PromiseA.promisifyAll(require('fs'))
 | 
			
		||||
  ;
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
var PromiseA = require("bluebird").Promise,
 | 
			
		||||
  fs = PromiseA.promisifyAll(require("fs"));
 | 
			
		||||
function create(Desi, options) {
 | 
			
		||||
  var fsapi = Desi.fsapi
 | 
			
		||||
    ;
 | 
			
		||||
 | 
			
		||||
  var fsapi = Desi.fsapi;
 | 
			
		||||
  options.blogdir = options.blogdir || options.working_path;
 | 
			
		||||
 | 
			
		||||
  fsapi.getMeta = function (dirnames, opts) {
 | 
			
		||||
    opts = opts || {};
 | 
			
		||||
 | 
			
		||||
    var extensions = ''
 | 
			
		||||
      , dotfiles = ''
 | 
			
		||||
      , contents = ''
 | 
			
		||||
      , sha1sum = ''
 | 
			
		||||
      ;
 | 
			
		||||
 | 
			
		||||
    var extensions = "",
 | 
			
		||||
      dotfiles = "",
 | 
			
		||||
      contents = "",
 | 
			
		||||
      sha1sum = "";
 | 
			
		||||
    if (Array.isArray(opts.extensions)) {
 | 
			
		||||
      extensions = '&extensions=' + opts.extensions.join(','); // md,markdown,jade,htm,html
 | 
			
		||||
      extensions = "&extensions=" + opts.extensions.join(","); // md,markdown,jade,htm,html
 | 
			
		||||
    }
 | 
			
		||||
    if (opts.dotfiles) {
 | 
			
		||||
      dotfiles = '&dotfiles=true';
 | 
			
		||||
      dotfiles = "&dotfiles=true";
 | 
			
		||||
    }
 | 
			
		||||
    if (opts.contents) {
 | 
			
		||||
      contents = '&contents=true';
 | 
			
		||||
      contents = "&contents=true";
 | 
			
		||||
    }
 | 
			
		||||
    if (false === opts.sha1sum) {
 | 
			
		||||
      sha1sum = '&sha1sum=false';
 | 
			
		||||
      sha1sum = "&sha1sum=false";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return fsapi.walk.walkDirs(options.blogdir, dirnames, opts);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  fsapi.getContents = function (filepaths) {
 | 
			
		||||
 | 
			
		||||
    return fsapi.getfs(options.blogdir, filepaths);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  fsapi.getCache = function () {
 | 
			
		||||
    return fs.readFileAsync(options.blogdir, '/cache.json').catch(function (/*e*/) {
 | 
			
		||||
      return {};
 | 
			
		||||
    }).then(function (obj) {
 | 
			
		||||
      return obj;
 | 
			
		||||
    });
 | 
			
		||||
    return fs
 | 
			
		||||
      .readFileAsync(options.blogdir, "/cache.json")
 | 
			
		||||
      .catch(function (/*e*/) {
 | 
			
		||||
        return {};
 | 
			
		||||
      })
 | 
			
		||||
      .then(function (obj) {
 | 
			
		||||
        return obj;
 | 
			
		||||
      });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  fsapi.copy = function (files) {
 | 
			
		||||
@ -55,14 +51,13 @@ function create(Desi, options) {
 | 
			
		||||
 | 
			
		||||
  fsapi.putFiles = function (files, opts) {
 | 
			
		||||
    files.forEach(function (file) {
 | 
			
		||||
      if (!file.contents || 'string' === typeof file.contents) {
 | 
			
		||||
      if (!file.contents || "string" === typeof file.contents) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      if (/\.json$/i.test(file.path)) {
 | 
			
		||||
        file.contents = JSON.stringify(file.contents);
 | 
			
		||||
      }
 | 
			
		||||
      else if (/\.ya?ml$/i.test(file.path)) {
 | 
			
		||||
        file.contents = Desi.YAML.stringify(file.contents); 
 | 
			
		||||
      } else if (/\.ya?ml$/i.test(file.path)) {
 | 
			
		||||
        file.contents = Desi.YAML.stringify(file.contents);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,18 +1,18 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
var PromiseA      = require('bluebird').Promise
 | 
			
		||||
  , fs            = PromiseA.promisifyAll(require('fs'))
 | 
			
		||||
  , forEachAsync  = require('foreachasync').forEachAsync
 | 
			
		||||
  , path          = require('path')
 | 
			
		||||
  , walk          = require('walk')
 | 
			
		||||
  , escapeRegExp  = require('escape-string-regexp')
 | 
			
		||||
  , safeResolve   = require('../utils').safeResolve
 | 
			
		||||
  , sha1sum       = function (str) { return require('secret-utils').hashsum('sha1', str); }
 | 
			
		||||
  , mkdirp        = PromiseA.promisify(require('mkdirp'))
 | 
			
		||||
  , fsExtra       = PromiseA.promisifyAll(require('fs.extra'))
 | 
			
		||||
  //, tmpdir        = require('os').tmpdir()
 | 
			
		||||
  ;
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
var PromiseA = require("bluebird").Promise,
 | 
			
		||||
  fs = PromiseA.promisifyAll(require("fs")),
 | 
			
		||||
  forEachAsync = require("foreachasync").forEachAsync,
 | 
			
		||||
  path = require("path"),
 | 
			
		||||
  walk = require("walk"),
 | 
			
		||||
  escapeRegExp = require("escape-string-regexp"),
 | 
			
		||||
  safeResolve = require("../utils").safeResolve,
 | 
			
		||||
  sha1sum = function (str) {
 | 
			
		||||
    return require("secret-utils").hashsum("sha1", str);
 | 
			
		||||
  },
 | 
			
		||||
  mkdirp = PromiseA.promisify(require("mkdirp")),
 | 
			
		||||
  fsExtra = PromiseA.promisifyAll(require("fs.extra"));
 | 
			
		||||
//, tmpdir        = require('os').tmpdir()
 | 
			
		||||
function strip(prefix, pathname) {
 | 
			
		||||
  return pathname.substr(prefix.length + 1);
 | 
			
		||||
}
 | 
			
		||||
@ -23,24 +23,24 @@ function walkDir(parent, sub, opts) {
 | 
			
		||||
    opts.sha1sum = true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  var prefix = path.resolve(parent)
 | 
			
		||||
    , trueRoot = path.resolve(prefix, sub)
 | 
			
		||||
    , files = []
 | 
			
		||||
    ;
 | 
			
		||||
 | 
			
		||||
  var prefix = path.resolve(parent),
 | 
			
		||||
    trueRoot = path.resolve(prefix, sub),
 | 
			
		||||
    files = [];
 | 
			
		||||
  function filter(name) {
 | 
			
		||||
    if (!name) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!opts.dotfiles && ('.' === name[0])) {
 | 
			
		||||
    if (!opts.dotfiles && "." === name[0]) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (opts.extensions && opts.extensions.length) {
 | 
			
		||||
      if (!opts.extensions.some(function (ext) {
 | 
			
		||||
        return new RegExp('\\.' + escapeRegExp(ext) + '$').test(name);
 | 
			
		||||
      })) {
 | 
			
		||||
      if (
 | 
			
		||||
        !opts.extensions.some(function (ext) {
 | 
			
		||||
          return new RegExp("\\." + escapeRegExp(ext) + "$").test(name);
 | 
			
		||||
        })
 | 
			
		||||
      ) {
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
@ -49,10 +49,8 @@ function walkDir(parent, sub, opts) {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return new PromiseA(function (resolve) {
 | 
			
		||||
    var walker = walk.walk(trueRoot)
 | 
			
		||||
      ;
 | 
			
		||||
 | 
			
		||||
    walker.on('nodeError', function (filepath, stat, next) {
 | 
			
		||||
    var walker = walk.walk(trueRoot);
 | 
			
		||||
    walker.on("nodeError", function (filepath, stat, next) {
 | 
			
		||||
      //stats.forEach(function (stat) {
 | 
			
		||||
      if (!filter(stat.name)) {
 | 
			
		||||
        return;
 | 
			
		||||
@ -60,40 +58,37 @@ function walkDir(parent, sub, opts) {
 | 
			
		||||
 | 
			
		||||
      stat.error.path = path.join(strip(prefix, filepath), stat.name);
 | 
			
		||||
      files.push({
 | 
			
		||||
        name: stat.name
 | 
			
		||||
      , relativePath: strip(prefix, filepath)
 | 
			
		||||
      , path: path.join(strip(prefix, filepath), stat.name)
 | 
			
		||||
        name: stat.name,
 | 
			
		||||
        relativePath: strip(prefix, filepath),
 | 
			
		||||
        path: path.join(strip(prefix, filepath), stat.name),
 | 
			
		||||
 | 
			
		||||
      , type: undefined
 | 
			
		||||
      , error: stat.error
 | 
			
		||||
        type: undefined,
 | 
			
		||||
        error: stat.error,
 | 
			
		||||
      });
 | 
			
		||||
      //});
 | 
			
		||||
 | 
			
		||||
      next();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    walker.on('files', function (root, stats, next) {
 | 
			
		||||
      var dirname = strip(prefix, root)
 | 
			
		||||
        ;
 | 
			
		||||
 | 
			
		||||
    walker.on("files", function (root, stats, next) {
 | 
			
		||||
      var dirname = strip(prefix, root);
 | 
			
		||||
      function eachFile(stat) {
 | 
			
		||||
        var file
 | 
			
		||||
          ;
 | 
			
		||||
        var file;
 | 
			
		||||
 | 
			
		||||
        if (!filter(stat.name)) {
 | 
			
		||||
          return PromiseA.resolve();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        file = {
 | 
			
		||||
          name: stat.name
 | 
			
		||||
        , relativePath: dirname
 | 
			
		||||
        , path: path.join(dirname, stat.name)
 | 
			
		||||
          name: stat.name,
 | 
			
		||||
          relativePath: dirname,
 | 
			
		||||
          path: path.join(dirname, stat.name),
 | 
			
		||||
 | 
			
		||||
        , createdDate: (stat.birthtime||stat.ctime).toISOString()
 | 
			
		||||
        , lastModifiedDate: stat.mtime.toISOString()
 | 
			
		||||
          createdDate: (stat.birthtime || stat.ctime).toISOString(),
 | 
			
		||||
          lastModifiedDate: stat.mtime.toISOString(),
 | 
			
		||||
 | 
			
		||||
        , size: stat.size
 | 
			
		||||
        , type: undefined // TODO include mimetype
 | 
			
		||||
          size: stat.size,
 | 
			
		||||
          type: undefined, // TODO include mimetype
 | 
			
		||||
        };
 | 
			
		||||
        files.push(file);
 | 
			
		||||
 | 
			
		||||
@ -102,17 +97,17 @@ function walkDir(parent, sub, opts) {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // TODO stream sha1 (for assets)
 | 
			
		||||
        return fs.readFileAsync(path.join(root, stat.name), null).then(function (buffer) {
 | 
			
		||||
          var contents = buffer.toString('utf8')
 | 
			
		||||
            ;
 | 
			
		||||
        return fs
 | 
			
		||||
          .readFileAsync(path.join(root, stat.name), null)
 | 
			
		||||
          .then(function (buffer) {
 | 
			
		||||
            var contents = buffer.toString("utf8");
 | 
			
		||||
            file.sha1 = sha1sum(contents);
 | 
			
		||||
            file.type = undefined;
 | 
			
		||||
 | 
			
		||||
          file.sha1 = sha1sum(contents);
 | 
			
		||||
          file.type = undefined;
 | 
			
		||||
 | 
			
		||||
          if (opts.contents) {
 | 
			
		||||
            file.contents = contents;
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
            if (opts.contents) {
 | 
			
		||||
              file.contents = contents;
 | 
			
		||||
            }
 | 
			
		||||
          });
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (!opts.contents) {
 | 
			
		||||
@ -125,7 +120,7 @@ function walkDir(parent, sub, opts) {
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    walker.on('end', function () {
 | 
			
		||||
    walker.on("end", function () {
 | 
			
		||||
      resolve(files);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
@ -134,9 +129,7 @@ function walkDir(parent, sub, opts) {
 | 
			
		||||
function walkDirs(parent, subs, opts) {
 | 
			
		||||
  opts = opts || {};
 | 
			
		||||
 | 
			
		||||
  var collections = {}
 | 
			
		||||
    ;
 | 
			
		||||
 | 
			
		||||
  var collections = {};
 | 
			
		||||
  return forEachAsync(subs, function (sub) {
 | 
			
		||||
    return walkDir(parent, sub, opts).then(function (results) {
 | 
			
		||||
      collections[sub] = results;
 | 
			
		||||
@ -146,59 +139,53 @@ function walkDirs(parent, subs, opts) {
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function getfs(blogdir, filepaths) {
 | 
			
		||||
  var files = []
 | 
			
		||||
    ;
 | 
			
		||||
 | 
			
		||||
  var files = [];
 | 
			
		||||
  return forEachAsync(filepaths, function (filepath) {
 | 
			
		||||
    var pathname = safeResolve(blogdir, filepath)
 | 
			
		||||
      ;
 | 
			
		||||
    var pathname = safeResolve(blogdir, filepath);
 | 
			
		||||
    return fs
 | 
			
		||||
      .lstatAsync(pathname)
 | 
			
		||||
      .then(function (stat) {
 | 
			
		||||
        return fs.readFileAsync(pathname, null).then(function (buffer) {
 | 
			
		||||
          files.push({
 | 
			
		||||
            name: path.basename(pathname),
 | 
			
		||||
            relativePath: path.dirname(filepath),
 | 
			
		||||
            path: filepath,
 | 
			
		||||
 | 
			
		||||
    return fs.lstatAsync(pathname).then(function (stat) {
 | 
			
		||||
      return fs.readFileAsync(pathname, null).then(function (buffer) {
 | 
			
		||||
            createdDate: (stat.birthtime || stat.ctime).toISOString(),
 | 
			
		||||
            lastModifiedDate: stat.mtime.toISOString(),
 | 
			
		||||
 | 
			
		||||
        files.push({
 | 
			
		||||
          name: path.basename(pathname)
 | 
			
		||||
        , relativePath: path.dirname(filepath)
 | 
			
		||||
        , path: filepath
 | 
			
		||||
 | 
			
		||||
        , createdDate: (stat.birthtime||stat.ctime).toISOString()
 | 
			
		||||
        , lastModifiedDate: stat.mtime.toISOString()
 | 
			
		||||
 | 
			
		||||
        , contents: buffer.toString('utf8')
 | 
			
		||||
        , size: buffer.length
 | 
			
		||||
        , sha1: sha1sum(buffer)
 | 
			
		||||
        , type: undefined
 | 
			
		||||
            contents: buffer.toString("utf8"),
 | 
			
		||||
            size: buffer.length,
 | 
			
		||||
            sha1: sha1sum(buffer),
 | 
			
		||||
            type: undefined,
 | 
			
		||||
          });
 | 
			
		||||
        });
 | 
			
		||||
      })
 | 
			
		||||
      .catch(function (e) {
 | 
			
		||||
        files.push({ path: filepath, error: e.message });
 | 
			
		||||
      });
 | 
			
		||||
    }).catch(function (e) {
 | 
			
		||||
      files.push({ path: filepath, error: e.message });
 | 
			
		||||
    });
 | 
			
		||||
  }).then(function () {
 | 
			
		||||
    return files;
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function makeAllDirs(dirpaths) {
 | 
			
		||||
  var errors = []
 | 
			
		||||
    ;
 | 
			
		||||
 | 
			
		||||
  var errors = [];
 | 
			
		||||
  return forEachAsync(dirpaths, function (pathname) {
 | 
			
		||||
    return mkdirp(pathname).catch(function (e) {
 | 
			
		||||
      // TODO exclude attempting to write files to this dir?
 | 
			
		||||
      errors.push({
 | 
			
		||||
        type: 'directory'
 | 
			
		||||
        type: "directory",
 | 
			
		||||
 | 
			
		||||
      , directory: pathname
 | 
			
		||||
        directory: pathname,
 | 
			
		||||
 | 
			
		||||
      , message: e.message
 | 
			
		||||
      , code: e.code
 | 
			
		||||
      , errno: e.errno
 | 
			
		||||
      , status: e.status
 | 
			
		||||
      , syscall: e.syscall
 | 
			
		||||
        message: e.message,
 | 
			
		||||
        code: e.code,
 | 
			
		||||
        errno: e.errno,
 | 
			
		||||
        status: e.status,
 | 
			
		||||
        syscall: e.syscall,
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    });
 | 
			
		||||
  }).then(function () {
 | 
			
		||||
    return errors;
 | 
			
		||||
@ -207,156 +194,164 @@ function makeAllDirs(dirpaths) {
 | 
			
		||||
 | 
			
		||||
function copyfs(blogdir, files) {
 | 
			
		||||
  // TODO switch format to { source: ..., dest: ..., opts: ... } ?
 | 
			
		||||
  var results = { errors: [] }
 | 
			
		||||
    , dirpaths = {}
 | 
			
		||||
    , sources = Object.keys(files)
 | 
			
		||||
    ;
 | 
			
		||||
 | 
			
		||||
  var results = { errors: [] },
 | 
			
		||||
    dirpaths = {},
 | 
			
		||||
    sources = Object.keys(files);
 | 
			
		||||
  return forEachAsync(sources, function (source) {
 | 
			
		||||
    /*
 | 
			
		||||
    var nsource = safeResolve(blogdir, source)
 | 
			
		||||
      ;
 | 
			
		||||
    */
 | 
			
		||||
 | 
			
		||||
    var dest = safeResolve(blogdir, files[source])
 | 
			
		||||
      , pathname = path.dirname(dest)
 | 
			
		||||
      //, filename = path.basename(dest)
 | 
			
		||||
      ;
 | 
			
		||||
 | 
			
		||||
    var dest = safeResolve(blogdir, files[source]),
 | 
			
		||||
      pathname = path.dirname(dest);
 | 
			
		||||
    //, filename = path.basename(dest)
 | 
			
		||||
    dirpaths[pathname] = true;
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    return PromiseA.resolve();
 | 
			
		||||
  }).then(function () {
 | 
			
		||||
    // TODO is it better to do this lazy-like or as a batch?
 | 
			
		||||
    // I figure as batch when there may be hundreds of files,
 | 
			
		||||
    // likely within 2 or 3 directories
 | 
			
		||||
    return makeAllDirs(Object.keys(dirpaths)).then(function (errors) {
 | 
			
		||||
      errors.forEach(function (e) {
 | 
			
		||||
        results.errors.push(e);
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  }).then(function () {
 | 
			
		||||
    // TODO allow delete?
 | 
			
		||||
    return forEachAsync(sources, function (source) {
 | 
			
		||||
      return fsExtra.copyAsync(
 | 
			
		||||
        safeResolve(blogdir, source)
 | 
			
		||||
      , safeResolve(blogdir, files[source])
 | 
			
		||||
      , { replace: true }
 | 
			
		||||
      ).catch(function (e) {
 | 
			
		||||
        results.errors.push({
 | 
			
		||||
          type: 'file'
 | 
			
		||||
 | 
			
		||||
        , source: source
 | 
			
		||||
        , destination: files[source]
 | 
			
		||||
 | 
			
		||||
        , message: e.message
 | 
			
		||||
        , code: e.code
 | 
			
		||||
        , errno: e.errno
 | 
			
		||||
        , status: e.status
 | 
			
		||||
        , syscall: e.syscall
 | 
			
		||||
  })
 | 
			
		||||
    .then(function () {
 | 
			
		||||
      // TODO is it better to do this lazy-like or as a batch?
 | 
			
		||||
      // I figure as batch when there may be hundreds of files,
 | 
			
		||||
      // likely within 2 or 3 directories
 | 
			
		||||
      return makeAllDirs(Object.keys(dirpaths)).then(function (errors) {
 | 
			
		||||
        errors.forEach(function (e) {
 | 
			
		||||
          results.errors.push(e);
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
    })
 | 
			
		||||
    .then(function () {
 | 
			
		||||
      // TODO allow delete?
 | 
			
		||||
      return forEachAsync(sources, function (source) {
 | 
			
		||||
        return fsExtra
 | 
			
		||||
          .copyAsync(
 | 
			
		||||
            safeResolve(blogdir, source),
 | 
			
		||||
            safeResolve(blogdir, files[source]),
 | 
			
		||||
            { replace: true }
 | 
			
		||||
          )
 | 
			
		||||
          .catch(function (e) {
 | 
			
		||||
            results.errors.push({
 | 
			
		||||
              type: "file",
 | 
			
		||||
 | 
			
		||||
              source: source,
 | 
			
		||||
              destination: files[source],
 | 
			
		||||
 | 
			
		||||
              message: e.message,
 | 
			
		||||
              code: e.code,
 | 
			
		||||
              errno: e.errno,
 | 
			
		||||
              status: e.status,
 | 
			
		||||
              syscall: e.syscall,
 | 
			
		||||
            });
 | 
			
		||||
          });
 | 
			
		||||
      });
 | 
			
		||||
    })
 | 
			
		||||
    .catch(function (e) {
 | 
			
		||||
      results.error = {
 | 
			
		||||
        message: e.message,
 | 
			
		||||
        code: e.code,
 | 
			
		||||
        errno: e.errno,
 | 
			
		||||
        status: e.status,
 | 
			
		||||
        syscall: e.syscall,
 | 
			
		||||
      };
 | 
			
		||||
    })
 | 
			
		||||
    .then(function () {
 | 
			
		||||
      return results;
 | 
			
		||||
    });
 | 
			
		||||
  }).catch(function (e) {
 | 
			
		||||
    results.error = {
 | 
			
		||||
      message: e.message
 | 
			
		||||
    , code: e.code
 | 
			
		||||
    , errno: e.errno
 | 
			
		||||
    , status: e.status
 | 
			
		||||
    , syscall: e.syscall
 | 
			
		||||
    };
 | 
			
		||||
  }).then(function () {
 | 
			
		||||
    return results;
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function putfs(blogdir, files, options) {
 | 
			
		||||
  options = options || {};
 | 
			
		||||
 | 
			
		||||
  var putfsResults = { errors: [] }
 | 
			
		||||
    , dirpaths = {}
 | 
			
		||||
    ;
 | 
			
		||||
 | 
			
		||||
  var putfsResults = { errors: [] },
 | 
			
		||||
    dirpaths = {};
 | 
			
		||||
  return forEachAsync(files, function (file) {
 | 
			
		||||
    var filepath = safeResolve(blogdir, file.path || path.join(file.relativePath, file.name))
 | 
			
		||||
      , pathname = path.dirname(filepath)
 | 
			
		||||
      , filename = file.name || path.basename(filepath)
 | 
			
		||||
      ;
 | 
			
		||||
 | 
			
		||||
    var filepath = safeResolve(
 | 
			
		||||
        blogdir,
 | 
			
		||||
        file.path || path.join(file.relativePath, file.name)
 | 
			
		||||
      ),
 | 
			
		||||
      pathname = path.dirname(filepath),
 | 
			
		||||
      filename = file.name || path.basename(filepath);
 | 
			
		||||
    file.realPath = filepath;
 | 
			
		||||
    file.name = filename;
 | 
			
		||||
 | 
			
		||||
    dirpaths[pathname] = true;
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    return PromiseA.resolve();
 | 
			
		||||
  }).then(function () {
 | 
			
		||||
    // TODO is it better to do this lazy-like or as a batch?
 | 
			
		||||
    // I figure as batch when there may be hundreds of files,
 | 
			
		||||
    // likely within 2 or 3 directories
 | 
			
		||||
    return forEachAsync(Object.keys(dirpaths), function (pathname) {
 | 
			
		||||
      return mkdirp(pathname).catch(function (e) {
 | 
			
		||||
        // TODO exclude attempting to write files to this dir?
 | 
			
		||||
        putfsResults.errors.push({
 | 
			
		||||
          type: 'directory'
 | 
			
		||||
  })
 | 
			
		||||
    .then(function () {
 | 
			
		||||
      // TODO is it better to do this lazy-like or as a batch?
 | 
			
		||||
      // I figure as batch when there may be hundreds of files,
 | 
			
		||||
      // likely within 2 or 3 directories
 | 
			
		||||
      return forEachAsync(Object.keys(dirpaths), function (pathname) {
 | 
			
		||||
        return mkdirp(pathname).catch(function (e) {
 | 
			
		||||
          // TODO exclude attempting to write files to this dir?
 | 
			
		||||
          putfsResults.errors.push({
 | 
			
		||||
            type: "directory",
 | 
			
		||||
 | 
			
		||||
        , directory: pathname
 | 
			
		||||
            directory: pathname,
 | 
			
		||||
 | 
			
		||||
        , message: e.message
 | 
			
		||||
        , code: e.code
 | 
			
		||||
        , errno: e.errno
 | 
			
		||||
        , status: e.status
 | 
			
		||||
        , syscall: e.syscall
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  }).then(function () {
 | 
			
		||||
    // TODO sort deletes last
 | 
			
		||||
    return forEachAsync(files, function (file) {
 | 
			
		||||
      // TODO use lastModifiedDate as per client request?
 | 
			
		||||
      // TODO compare sha1 sums for integrity
 | 
			
		||||
      // NOTE existsAsync is backwards
 | 
			
		||||
      return fs.existsAsync(file.realPath).then(function () {
 | 
			
		||||
        return fs.writeFileAsync(file.realPath, file.contents, 'utf8');
 | 
			
		||||
      }).catch(function (/*exists*/) {
 | 
			
		||||
        if (file.delete || !file.contents) {
 | 
			
		||||
          return fs.unlinkAsync(file.realPath);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (false === options.replace || false === options.overwrite) {
 | 
			
		||||
          throw new Error('EEXIST: the file already exists');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return fs.writeFileAsync(file.realPath, file.contents, 'utf8');
 | 
			
		||||
      }).catch(function (e) {
 | 
			
		||||
        putfsResults.errors.push({
 | 
			
		||||
          type: 'file'
 | 
			
		||||
 | 
			
		||||
        , file: file.realPath
 | 
			
		||||
        , delete: !file.contents
 | 
			
		||||
        , path: file.path
 | 
			
		||||
        , relativePath: file.relativePath
 | 
			
		||||
        , name: file.name
 | 
			
		||||
 | 
			
		||||
        , message: e.message
 | 
			
		||||
        , code: e.code
 | 
			
		||||
        , errno: e.errno
 | 
			
		||||
        , status: e.status
 | 
			
		||||
        , syscall: e.syscall
 | 
			
		||||
            message: e.message,
 | 
			
		||||
            code: e.code,
 | 
			
		||||
            errno: e.errno,
 | 
			
		||||
            status: e.status,
 | 
			
		||||
            syscall: e.syscall,
 | 
			
		||||
          });
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
    })
 | 
			
		||||
    .then(function () {
 | 
			
		||||
      // TODO sort deletes last
 | 
			
		||||
      return forEachAsync(files, function (file) {
 | 
			
		||||
        // TODO use lastModifiedDate as per client request?
 | 
			
		||||
        // TODO compare sha1 sums for integrity
 | 
			
		||||
        // NOTE existsAsync is backwards
 | 
			
		||||
        return fs
 | 
			
		||||
          .existsAsync(file.realPath)
 | 
			
		||||
          .then(function () {
 | 
			
		||||
            return fs.writeFileAsync(file.realPath, file.contents, "utf8");
 | 
			
		||||
          })
 | 
			
		||||
          .catch(function (/*exists*/) {
 | 
			
		||||
            if (file.delete || !file.contents) {
 | 
			
		||||
              return fs.unlinkAsync(file.realPath);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (false === options.replace || false === options.overwrite) {
 | 
			
		||||
              throw new Error("EEXIST: the file already exists");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return fs.writeFileAsync(file.realPath, file.contents, "utf8");
 | 
			
		||||
          })
 | 
			
		||||
          .catch(function (e) {
 | 
			
		||||
            putfsResults.errors.push({
 | 
			
		||||
              type: "file",
 | 
			
		||||
 | 
			
		||||
              file: file.realPath,
 | 
			
		||||
              delete: !file.contents,
 | 
			
		||||
              path: file.path,
 | 
			
		||||
              relativePath: file.relativePath,
 | 
			
		||||
              name: file.name,
 | 
			
		||||
 | 
			
		||||
              message: e.message,
 | 
			
		||||
              code: e.code,
 | 
			
		||||
              errno: e.errno,
 | 
			
		||||
              status: e.status,
 | 
			
		||||
              syscall: e.syscall,
 | 
			
		||||
            });
 | 
			
		||||
          });
 | 
			
		||||
      });
 | 
			
		||||
    })
 | 
			
		||||
    .catch(function (e) {
 | 
			
		||||
      putfsResults.error = {
 | 
			
		||||
        message: e.message,
 | 
			
		||||
        code: e.code,
 | 
			
		||||
        errno: e.errno,
 | 
			
		||||
        status: e.status,
 | 
			
		||||
        syscall: e.syscall,
 | 
			
		||||
      };
 | 
			
		||||
    })
 | 
			
		||||
    .then(function () {
 | 
			
		||||
      return putfsResults;
 | 
			
		||||
    });
 | 
			
		||||
  }).catch(function (e) {
 | 
			
		||||
    putfsResults.error = {
 | 
			
		||||
      message: e.message
 | 
			
		||||
    , code: e.code
 | 
			
		||||
    , errno: e.errno
 | 
			
		||||
    , status: e.status
 | 
			
		||||
    , syscall: e.syscall
 | 
			
		||||
    };
 | 
			
		||||
  }).then(function () {
 | 
			
		||||
    return putfsResults;
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
/*
 | 
			
		||||
walkDirs('blog', ['posts'], { contents: false }).then(function (stats) {
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
exports.fsapi = require('./fsapi');
 | 
			
		||||
exports.sha1sum = require('./sha1sum').sha1sum;
 | 
			
		||||
exports.realFsapi = require('./fsapi-real');
 | 
			
		||||
exports.fsapi = require("./fsapi");
 | 
			
		||||
exports.sha1sum = require("./sha1sum").sha1sum;
 | 
			
		||||
exports.realFsapi = require("./fsapi-real");
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,7 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
var PromiseA = require('bluebird').Promise
 | 
			
		||||
  , secretutils = require('secret-utils')
 | 
			
		||||
  ;
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
var PromiseA = require("bluebird").Promise,
 | 
			
		||||
  secretutils = require("secret-utils");
 | 
			
		||||
module.exports.sha1sum = function (str) {
 | 
			
		||||
  return PromiseA.resolve( secretutils.hashsum('sha1', str) );
 | 
			
		||||
  return PromiseA.resolve(secretutils.hashsum("sha1", str));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -1,38 +1,35 @@
 | 
			
		||||
/*jshint -W054 */
 | 
			
		||||
;(function (exports) {
 | 
			
		||||
  'use strict';
 | 
			
		||||
 | 
			
		||||
  var PromiseA = exports.Promise || require('bluebird').Promise
 | 
			
		||||
    ;
 | 
			
		||||
 | 
			
		||||
  function renderMd(contentstr/*, desi*/) {
 | 
			
		||||
    var markitdown = (exports.markdownit || require('markdown-it'))({ html: true, linkify: true })
 | 
			
		||||
      ;
 | 
			
		||||
(function (exports) {
 | 
			
		||||
  "use strict";
 | 
			
		||||
 | 
			
		||||
  var PromiseA = exports.Promise || require("bluebird").Promise;
 | 
			
		||||
  function renderMd(contentstr /*, desi*/) {
 | 
			
		||||
    var markitdown = (exports.markdownit || require("markdown-it"))({
 | 
			
		||||
      html: true,
 | 
			
		||||
      linkify: true,
 | 
			
		||||
    });
 | 
			
		||||
    return PromiseA.resolve(
 | 
			
		||||
      markitdown.render(contentstr)
 | 
			
		||||
        //.replace('"', '"')
 | 
			
		||||
        //.replace(''', "'")
 | 
			
		||||
        //.replace('/', '/')
 | 
			
		||||
      //.replace('"', '"')
 | 
			
		||||
      //.replace(''', "'")
 | 
			
		||||
      //.replace('/', '/')
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function renderNoop(contentstr/*, desi*/) {
 | 
			
		||||
  function renderNoop(contentstr /*, desi*/) {
 | 
			
		||||
    // hmmm... that was easy
 | 
			
		||||
    return PromiseA.resolve(contentstr);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function renderJade(contentstr, desi, options) {
 | 
			
		||||
    options = options || {};
 | 
			
		||||
    if (!('pretty' in options)) {
 | 
			
		||||
    if (!("pretty" in options)) {
 | 
			
		||||
      options.pretty = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    var jade = (exports.jade || require('jade'))
 | 
			
		||||
      , fn = jade.compile(contentstr, options)
 | 
			
		||||
      , html = fn(desi)
 | 
			
		||||
      ;
 | 
			
		||||
 | 
			
		||||
    var jade = exports.jade || require("jade"),
 | 
			
		||||
      fn = jade.compile(contentstr, options),
 | 
			
		||||
      html = fn(desi);
 | 
			
		||||
    return PromiseA.resolve(html);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -41,4 +38,4 @@
 | 
			
		||||
  exports.DesiraeRenderCss = renderNoop.DesiraeRenderCss = renderNoop;
 | 
			
		||||
  exports.DesiraeRenderJs = renderNoop.DesiraeRenderJs = renderNoop;
 | 
			
		||||
  exports.DesiraeRenderJade = renderJade.DesiraeRenderJade = renderJade;
 | 
			
		||||
}('undefined' !== typeof exports && exports || window));
 | 
			
		||||
})(("undefined" !== typeof exports && exports) || window);
 | 
			
		||||
 | 
			
		||||
@ -1,143 +1,153 @@
 | 
			
		||||
/*jshint -W054 */
 | 
			
		||||
;(function (exports) {
 | 
			
		||||
  'use strict';
 | 
			
		||||
 | 
			
		||||
  var cores = {}
 | 
			
		||||
    , Desi = exports.Desirae || require('desirae').Desirae
 | 
			
		||||
    , path          = exports.path          || require('path')
 | 
			
		||||
    ;
 | 
			
		||||
(function (exports) {
 | 
			
		||||
  "use strict";
 | 
			
		||||
 | 
			
		||||
  var cores = {},
 | 
			
		||||
    Desi = exports.Desirae || require("desirae").Desirae,
 | 
			
		||||
    path = exports.path || require("path");
 | 
			
		||||
  cores.lint = function (desi, env, collection, entity) {
 | 
			
		||||
    // TODO splice
 | 
			
		||||
    //desi.content.collections = desi.content.collections.filter(function (entity) {
 | 
			
		||||
      // TODO throw for any files that don't have a registered renderer
 | 
			
		||||
      if (!entity.yml) {
 | 
			
		||||
        if (!desi.config.empty_frontmatter) {
 | 
			
		||||
          throw new Error("no frontmatter for " + (entity.path || entity.name) + "."
 | 
			
		||||
            + "Set `config.yml.empty_frontmatter: include|skip` to ignore this error."
 | 
			
		||||
          );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ('include' === desi.config.empty_frontmatter) {
 | 
			
		||||
          entity.yml = {};
 | 
			
		||||
        }
 | 
			
		||||
        else if ('skip' === desi.config.empty_frontmatter) {
 | 
			
		||||
          return false;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
          throw new Error('unrecognize option ' + desi.config.empty_frontmatter + 
 | 
			
		||||
            ' for `config.yml.empty_frontmatter: include|skip`.');
 | 
			
		||||
        }
 | 
			
		||||
    // TODO throw for any files that don't have a registered renderer
 | 
			
		||||
    if (!entity.yml) {
 | 
			
		||||
      if (!desi.config.empty_frontmatter) {
 | 
			
		||||
        throw new Error(
 | 
			
		||||
          "no frontmatter for " +
 | 
			
		||||
            (entity.path || entity.name) +
 | 
			
		||||
            "." +
 | 
			
		||||
            "Set `config.yml.empty_frontmatter: include|skip` to ignore this error."
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (!entity.body || !entity.body.trim()) {
 | 
			
		||||
        if (!desi.config.empty_body) {
 | 
			
		||||
          throw new Error('empty content file ' + (entity.path || entity.name)
 | 
			
		||||
            + '. Set `config.yml.empty_body: include|skip` to ignore this error.'
 | 
			
		||||
          );
 | 
			
		||||
        }
 | 
			
		||||
      if ("include" === desi.config.empty_frontmatter) {
 | 
			
		||||
        entity.yml = {};
 | 
			
		||||
      } else if ("skip" === desi.config.empty_frontmatter) {
 | 
			
		||||
        return false;
 | 
			
		||||
      } else {
 | 
			
		||||
        throw new Error(
 | 
			
		||||
          "unrecognize option " +
 | 
			
		||||
            desi.config.empty_frontmatter +
 | 
			
		||||
            " for `config.yml.empty_frontmatter: include|skip`."
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        if ('include' === desi.config.empty_body) {
 | 
			
		||||
          entity.body = '';
 | 
			
		||||
        }
 | 
			
		||||
        else if ('skip' === desi.config.empty_body) {
 | 
			
		||||
          return false;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
          throw new Error('unrecognize option ' + desi.config.empty_frontmatter + 
 | 
			
		||||
            ' for `config.yml.empty_body: include|skip`.');
 | 
			
		||||
        }
 | 
			
		||||
    if (!entity.body || !entity.body.trim()) {
 | 
			
		||||
      if (!desi.config.empty_body) {
 | 
			
		||||
        throw new Error(
 | 
			
		||||
          "empty content file " +
 | 
			
		||||
            (entity.path || entity.name) +
 | 
			
		||||
            ". Set `config.yml.empty_body: include|skip` to ignore this error."
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return true;
 | 
			
		||||
      if ("include" === desi.config.empty_body) {
 | 
			
		||||
        entity.body = "";
 | 
			
		||||
      } else if ("skip" === desi.config.empty_body) {
 | 
			
		||||
        return false;
 | 
			
		||||
      } else {
 | 
			
		||||
        throw new Error(
 | 
			
		||||
          "unrecognize option " +
 | 
			
		||||
            desi.config.empty_frontmatter +
 | 
			
		||||
            " for `config.yml.empty_body: include|skip`."
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
    //});
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  cores.root = function (desi, env, collection, entity) {
 | 
			
		||||
    entity.yml = entity.yml || {};
 | 
			
		||||
 | 
			
		||||
    entity.layout = entity.yml.layout || '__page__';
 | 
			
		||||
    entity.layout = entity.yml.layout || "__page__";
 | 
			
		||||
 | 
			
		||||
    // _root is not subject to the same permalink rules as collections,
 | 
			
		||||
    // so we just go ahead and define that here
 | 
			
		||||
    if (/^index\.\w+$/.test(entity.path)) {
 | 
			
		||||
      entity.permalink = '/';
 | 
			
		||||
      entity.permalink = "/";
 | 
			
		||||
    } else {
 | 
			
		||||
      entity.permalink = entity.yml.permalink || entity.path.replace(/\.\w+$/, '/');
 | 
			
		||||
      entity.permalink =
 | 
			
		||||
        entity.yml.permalink || entity.path.replace(/\.\w+$/, "/");
 | 
			
		||||
      entity.redirects = entity.redirects || [];
 | 
			
		||||
      entity.redirects.push(entity.permalink.replace(/\/$/, '/index.html'));
 | 
			
		||||
      entity.redirects.push(entity.permalink.replace(/\/$/, "/index.html"));
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  cores.normalize = function (desi, env, collection, entity) {
 | 
			
		||||
    entity.title          = entity.yml.title || Desi.firstCap(entity.name.replace(/\.\w+$/, ''));
 | 
			
		||||
    entity.date           = entity.yml.date;
 | 
			
		||||
    entity.title =
 | 
			
		||||
      entity.yml.title || Desi.firstCap(entity.name.replace(/\.\w+$/, ""));
 | 
			
		||||
    entity.date = entity.yml.date;
 | 
			
		||||
 | 
			
		||||
    if (!entity.date) {
 | 
			
		||||
      // TODO tell YAML parser to keep the date a string
 | 
			
		||||
      entity.date = new Date(entity.yml.created_at
 | 
			
		||||
        || entity.yml.time
 | 
			
		||||
        || entity.yml.updated_at
 | 
			
		||||
        || entity.createdDate
 | 
			
		||||
        || entity.lastModifiedDate
 | 
			
		||||
      entity.date = new Date(
 | 
			
		||||
        entity.yml.created_at ||
 | 
			
		||||
          entity.yml.time ||
 | 
			
		||||
          entity.yml.updated_at ||
 | 
			
		||||
          entity.createdDate ||
 | 
			
		||||
          entity.lastModifiedDate
 | 
			
		||||
      ).toISOString();
 | 
			
		||||
    }
 | 
			
		||||
    if ('object' === typeof entity.date) {
 | 
			
		||||
    if ("object" === typeof entity.date) {
 | 
			
		||||
      entity.date = entity.date.toISOString();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    entity.updated_at     = entity.yml.updated_at || entity.lastModifiedDate;
 | 
			
		||||
    entity.updated_at = entity.yml.updated_at || entity.lastModifiedDate;
 | 
			
		||||
 | 
			
		||||
    entity.published_at   = Desi.fromLocaleDate(entity.date || entity.lastModifiedDate);
 | 
			
		||||
    entity.year           = entity.published_at.year;
 | 
			
		||||
    entity.month          = entity.published_at.month;
 | 
			
		||||
    entity.day            = entity.published_at.day;
 | 
			
		||||
    entity.hour           = entity.published_at.hour;
 | 
			
		||||
    entity.twelve_hour    = entity.published_at.twelve_hour;
 | 
			
		||||
    entity.meridian       = entity.published_at.meridian;
 | 
			
		||||
    entity.minute         = entity.published_at.minute;
 | 
			
		||||
    entity.published_at = Desi.fromLocaleDate(
 | 
			
		||||
      entity.date || entity.lastModifiedDate
 | 
			
		||||
    );
 | 
			
		||||
    entity.year = entity.published_at.year;
 | 
			
		||||
    entity.month = entity.published_at.month;
 | 
			
		||||
    entity.day = entity.published_at.day;
 | 
			
		||||
    entity.hour = entity.published_at.hour;
 | 
			
		||||
    entity.twelve_hour = entity.published_at.twelve_hour;
 | 
			
		||||
    entity.meridian = entity.published_at.meridian;
 | 
			
		||||
    entity.minute = entity.published_at.minute;
 | 
			
		||||
    // let's just agree that that's too far
 | 
			
		||||
    //entity.second = entity.published_at.second;
 | 
			
		||||
 | 
			
		||||
    entity.slug           = Desi.slugify(entity.title);
 | 
			
		||||
    entity.slug_path      = Desi.slugifyPath(entity.relativePath);
 | 
			
		||||
    entity.slugPath       = Desi.slugifyPath(entity.relativePath);
 | 
			
		||||
    entity.slug = Desi.slugify(entity.title);
 | 
			
		||||
    entity.slug_path = Desi.slugifyPath(entity.relativePath);
 | 
			
		||||
    entity.slugPath = Desi.slugifyPath(entity.relativePath);
 | 
			
		||||
    // TODO type checking like below
 | 
			
		||||
    entity.redirects      = Array.isArray(entity.yml.redirects) && entity.yml.redirects|| [];
 | 
			
		||||
    entity.redirects =
 | 
			
		||||
      (Array.isArray(entity.yml.redirects) && entity.yml.redirects) || [];
 | 
			
		||||
 | 
			
		||||
    // categories
 | 
			
		||||
    if (Array.isArray(entity.yml.categories)) {
 | 
			
		||||
      entity.categories   = entity.yml.categories;
 | 
			
		||||
    }
 | 
			
		||||
    else if ('string' === typeof entity.yml.categories) {
 | 
			
		||||
      entity.categories   = [entity.yml.categories];
 | 
			
		||||
    }
 | 
			
		||||
    else if ('string' === typeof entity.yml.category) {
 | 
			
		||||
      entity.categories   = [entity.yml.category];
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      entity.categories   = [];
 | 
			
		||||
      entity.categories = entity.yml.categories;
 | 
			
		||||
    } else if ("string" === typeof entity.yml.categories) {
 | 
			
		||||
      entity.categories = [entity.yml.categories];
 | 
			
		||||
    } else if ("string" === typeof entity.yml.category) {
 | 
			
		||||
      entity.categories = [entity.yml.category];
 | 
			
		||||
    } else {
 | 
			
		||||
      entity.categories = [];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // tags
 | 
			
		||||
    if (Array.isArray(entity.yml.tags)) {
 | 
			
		||||
      entity.tags         = entity.yml.tags;
 | 
			
		||||
    }
 | 
			
		||||
    else if ('string' === typeof entity.yml.tags) {
 | 
			
		||||
      entity.tags         = [entity.yml.tags];
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      entity.tags         = [];
 | 
			
		||||
      entity.tags = entity.yml.tags;
 | 
			
		||||
    } else if ("string" === typeof entity.yml.tags) {
 | 
			
		||||
      entity.tags = [entity.yml.tags];
 | 
			
		||||
    } else {
 | 
			
		||||
      entity.tags = [];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    entity.permalink      = entity.permalink || entity.yml.permalink;
 | 
			
		||||
    entity.permalink = entity.permalink || entity.yml.permalink;
 | 
			
		||||
 | 
			
		||||
    if (!entity.permalink) {
 | 
			
		||||
      // try the fallback_permalink first (because we're looking at files that don't have yml)
 | 
			
		||||
      // then try the normal permalink (because :filename -> :title and whatnot, so it'll work)
 | 
			
		||||
      entity.permalink = Desi.permalinkify(desi, collection.fallback_permalink || collection.permalink, entity);
 | 
			
		||||
      entity.permalink = Desi.permalinkify(
 | 
			
		||||
        desi,
 | 
			
		||||
        collection.fallback_permalink || collection.permalink,
 | 
			
		||||
        entity
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
    if (!/\.x?html?$/.test(entity.permalink)) {
 | 
			
		||||
      entity.htmllink = path.join(entity.permalink, 'index.html');
 | 
			
		||||
@ -145,38 +155,51 @@
 | 
			
		||||
    */
 | 
			
		||||
 | 
			
		||||
    // relative to the site
 | 
			
		||||
    entity.relative_file  = path.join(env.base_path, entity.permalink)
 | 
			
		||||
                              .replace(/\/$/, '/index.html');
 | 
			
		||||
    entity.relative_href  = path.join(env.base_path, entity.permalink)
 | 
			
		||||
                              .replace(/\/index\.html$/, '/');
 | 
			
		||||
    entity.relative_link  = entity.relative_href;
 | 
			
		||||
    entity.relative_file = path
 | 
			
		||||
      .join(env.base_path, entity.permalink)
 | 
			
		||||
      .replace(/\/$/, "/index.html");
 | 
			
		||||
    entity.relative_href = path
 | 
			
		||||
      .join(env.base_path, entity.permalink)
 | 
			
		||||
      .replace(/\/index\.html$/, "/");
 | 
			
		||||
    entity.relative_link = entity.relative_href;
 | 
			
		||||
 | 
			
		||||
    entity.url            = env.base_url + path.join(env.base_path, entity.permalink)
 | 
			
		||||
                              .replace(/\/index\.html$/, '/');
 | 
			
		||||
    entity.canonical_url  = env.base_url + path.join(env.base_path, entity.permalink)
 | 
			
		||||
                              .replace(/\/index\.html$/, '/');
 | 
			
		||||
    entity.production_url = desi.site.base_url + path.join(desi.site.base_path, entity.permalink)
 | 
			
		||||
                              .replace(/\/index\.html$/, '/');
 | 
			
		||||
    entity.relative_url   = path.join(env.base_path, entity.permalink)
 | 
			
		||||
                              .replace(/\/index\.html$/, '/');
 | 
			
		||||
    entity.url =
 | 
			
		||||
      env.base_url +
 | 
			
		||||
      path.join(env.base_path, entity.permalink).replace(/\/index\.html$/, "/");
 | 
			
		||||
    entity.canonical_url =
 | 
			
		||||
      env.base_url +
 | 
			
		||||
      path.join(env.base_path, entity.permalink).replace(/\/index\.html$/, "/");
 | 
			
		||||
    entity.production_url =
 | 
			
		||||
      desi.site.base_url +
 | 
			
		||||
      path
 | 
			
		||||
        .join(desi.site.base_path, entity.permalink)
 | 
			
		||||
        .replace(/\/index\.html$/, "/");
 | 
			
		||||
    entity.relative_url = path
 | 
			
		||||
      .join(env.base_path, entity.permalink)
 | 
			
		||||
      .replace(/\/index\.html$/, "/");
 | 
			
		||||
 | 
			
		||||
    if (env.explicitIndexes || env.explicitIndices || env.explicit_indexes || env.explicit_indices) {
 | 
			
		||||
    if (
 | 
			
		||||
      env.explicitIndexes ||
 | 
			
		||||
      env.explicitIndices ||
 | 
			
		||||
      env.explicit_indexes ||
 | 
			
		||||
      env.explicit_indices
 | 
			
		||||
    ) {
 | 
			
		||||
      // NOTE: file_url is NOT replaced
 | 
			
		||||
      ['url', 'canonical_url', 'production_url', 'relative_url'].forEach(function (url) {
 | 
			
		||||
        entity[url] = entity[url].replace(/\/$/, '/index.html');
 | 
			
		||||
      });
 | 
			
		||||
      ["url", "canonical_url", "production_url", "relative_url"].forEach(
 | 
			
		||||
        function (url) {
 | 
			
		||||
          entity[url] = entity[url].replace(/\/$/, "/index.html");
 | 
			
		||||
        }
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // i.e. bootstrap, hero page, darkly
 | 
			
		||||
    entity.theme          = entity.theme || entity.yml.theme;
 | 
			
		||||
    entity.layout         = entity.layout || entity.yml.layout;
 | 
			
		||||
    entity.swatch         = entity.swatch || entity.yml.swatch;
 | 
			
		||||
    entity.theme = entity.theme || entity.yml.theme;
 | 
			
		||||
    entity.layout = entity.layout || entity.yml.layout;
 | 
			
		||||
    entity.swatch = entity.swatch || entity.yml.swatch;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  cores.disqus = function (desi, env, collection, entity) {
 | 
			
		||||
    var yml = entity.yml
 | 
			
		||||
      ;
 | 
			
		||||
 | 
			
		||||
    var yml = entity.yml;
 | 
			
		||||
    if (yml.uuid) {
 | 
			
		||||
      entity.disqus_identifier = yml.uuid;
 | 
			
		||||
    }
 | 
			
		||||
@ -184,4 +207,4 @@
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  exports.DesiraeTransformCore = cores.DesiraeTransformCore = cores;
 | 
			
		||||
}('undefined' !== typeof exports && exports || window));
 | 
			
		||||
})(("undefined" !== typeof exports && exports) || window);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										101
									
								
								lib/utils.js
									
									
									
									
									
								
							
							
						
						
									
										101
									
								
								lib/utils.js
									
									
									
									
									
								
							@ -1,9 +1,7 @@
 | 
			
		||||
;(function (exports) {
 | 
			
		||||
  'use strict';
 | 
			
		||||
 | 
			
		||||
  var path  = exports.path  || require('path')
 | 
			
		||||
    ;
 | 
			
		||||
(function (exports) {
 | 
			
		||||
  "use strict";
 | 
			
		||||
 | 
			
		||||
  var path = exports.path || require("path");
 | 
			
		||||
  function escapeRegExp(str) {
 | 
			
		||||
    return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
 | 
			
		||||
  }
 | 
			
		||||
@ -11,10 +9,8 @@
 | 
			
		||||
  function safeResolve(basename, target) {
 | 
			
		||||
    basename = path.resolve(basename);
 | 
			
		||||
 | 
			
		||||
    var targetname = path.resolve(basename, target)
 | 
			
		||||
      , re = new RegExp('^' + escapeRegExp(basename) + '(/|$)')
 | 
			
		||||
      ;
 | 
			
		||||
 | 
			
		||||
    var targetname = path.resolve(basename, target),
 | 
			
		||||
      re = new RegExp("^" + escapeRegExp(basename) + "(/|$)");
 | 
			
		||||
    return re.test(targetname) && targetname;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -22,29 +18,24 @@
 | 
			
		||||
  exports.escapeRegExp = escapeRegExp;
 | 
			
		||||
 | 
			
		||||
  function create(Desi) {
 | 
			
		||||
    var fsapi = Desi.fsapi || require('./node-adapters').fsapi
 | 
			
		||||
      ;
 | 
			
		||||
 | 
			
		||||
    var fsapi = Desi.fsapi || require("./node-adapters").fsapi;
 | 
			
		||||
    fsapi.getConfigs = function (confs) {
 | 
			
		||||
      var opts = { extensions: ['yml', 'yaml', 'json'], dotfiles: false, contents: true, sha1sum: true }
 | 
			
		||||
        ;
 | 
			
		||||
 | 
			
		||||
      var opts = {
 | 
			
		||||
        extensions: ["yml", "yaml", "json"],
 | 
			
		||||
        dotfiles: false,
 | 
			
		||||
        contents: true,
 | 
			
		||||
        sha1sum: true,
 | 
			
		||||
      };
 | 
			
		||||
      return fsapi.getMeta(confs, opts).then(function (collections) {
 | 
			
		||||
        var obj = {}
 | 
			
		||||
          ;
 | 
			
		||||
 | 
			
		||||
        var obj = {};
 | 
			
		||||
        Object.keys(collections).forEach(function (key) {
 | 
			
		||||
          var files = collections[key]
 | 
			
		||||
            , keyname = key.replace(/\.(json|ya?ml|\/)$/i, '')
 | 
			
		||||
            ;
 | 
			
		||||
 | 
			
		||||
          var files = collections[key],
 | 
			
		||||
            keyname = key.replace(/\.(json|ya?ml|\/)$/i, "");
 | 
			
		||||
          obj[keyname] = obj[keyname] || {};
 | 
			
		||||
 | 
			
		||||
          files.forEach(function (file) {
 | 
			
		||||
            var filename = file.name.replace(/\.(json|ya?ml)$/i, '')
 | 
			
		||||
              , data = {}
 | 
			
		||||
              ;
 | 
			
		||||
 | 
			
		||||
            var filename = file.name.replace(/\.(json|ya?ml)$/i, ""),
 | 
			
		||||
              data = {};
 | 
			
		||||
            if (file.error) {
 | 
			
		||||
              console.error(file);
 | 
			
		||||
              console.error(file.error);
 | 
			
		||||
@ -57,17 +48,16 @@
 | 
			
		||||
                if ("undefined" === data) {
 | 
			
		||||
                  data = {};
 | 
			
		||||
                }
 | 
			
		||||
              } catch(e) {
 | 
			
		||||
              } catch (e) {
 | 
			
		||||
                data = { error: e };
 | 
			
		||||
                console.error("Could not parse yaml for " + filename);
 | 
			
		||||
                console.error(file);
 | 
			
		||||
                console.error(e);
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
            else if (/\.(json)$/i.test(file.name)) {
 | 
			
		||||
            } else if (/\.(json)$/i.test(file.name)) {
 | 
			
		||||
              try {
 | 
			
		||||
                data = JSON.parse(file.contents) || {};
 | 
			
		||||
              } catch(e) {
 | 
			
		||||
              } catch (e) {
 | 
			
		||||
                data = { error: e };
 | 
			
		||||
                console.error("Could not parse json for " + filename);
 | 
			
		||||
                console.error(file);
 | 
			
		||||
@ -99,36 +89,34 @@
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    fsapi.getAllPartials = function () {
 | 
			
		||||
      return fsapi.getConfigs(['partials', 'partials.yml']).then(function (results) {
 | 
			
		||||
        var partials = {}
 | 
			
		||||
          ;
 | 
			
		||||
      return fsapi
 | 
			
		||||
        .getConfigs(["partials", "partials.yml"])
 | 
			
		||||
        .then(function (results) {
 | 
			
		||||
          var partials = {};
 | 
			
		||||
          Object.keys(results.partials).forEach(function (key) {
 | 
			
		||||
            var partial = results.partials[key];
 | 
			
		||||
            Object.keys(partial).forEach(function (prop) {
 | 
			
		||||
              if (partials[prop]) {
 | 
			
		||||
                console.warn("partial '" + prop + "' overwritten by " + key);
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
        Object.keys(results.partials).forEach(function (key) {
 | 
			
		||||
          var partial = results.partials[key]
 | 
			
		||||
            ;
 | 
			
		||||
 | 
			
		||||
          Object.keys(partial).forEach(function (prop) {
 | 
			
		||||
            if (partials[prop]) {
 | 
			
		||||
              console.warn('partial \'' + prop + '\' overwritten by ' + key);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            partials[prop] = partial[prop];
 | 
			
		||||
              partials[prop] = partial[prop];
 | 
			
		||||
            });
 | 
			
		||||
          });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return partials;
 | 
			
		||||
      });
 | 
			
		||||
          return partials;
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    fsapi.getAllConfigFiles = function () {
 | 
			
		||||
      return fsapi.getConfigs(['config.yml', 'site.yml', 'authors']).then(function (results) {
 | 
			
		||||
        var authors = results.authors
 | 
			
		||||
          , config = results.config.config
 | 
			
		||||
          , site = results.site.site
 | 
			
		||||
          ;
 | 
			
		||||
 | 
			
		||||
        return { config: config, authors: authors, site: site };
 | 
			
		||||
      });
 | 
			
		||||
      return fsapi
 | 
			
		||||
        .getConfigs(["config.yml", "site.yml", "authors"])
 | 
			
		||||
        .then(function (results) {
 | 
			
		||||
          var authors = results.authors,
 | 
			
		||||
            config = results.config.config,
 | 
			
		||||
            site = results.site.site;
 | 
			
		||||
          return { config: config, authors: authors, site: site };
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return exports;
 | 
			
		||||
@ -136,8 +124,7 @@
 | 
			
		||||
 | 
			
		||||
  if (exports.Desirae) {
 | 
			
		||||
    create(exports.Desirae);
 | 
			
		||||
  }
 | 
			
		||||
  else {
 | 
			
		||||
  } else {
 | 
			
		||||
    exports.create = create;
 | 
			
		||||
  }
 | 
			
		||||
}('undefined' !== typeof exports && exports || window));
 | 
			
		||||
})(("undefined" !== typeof exports && exports) || window);
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
;(function (exports) {
 | 
			
		||||
  'use strict';
 | 
			
		||||
(function (exports) {
 | 
			
		||||
  "use strict";
 | 
			
		||||
 | 
			
		||||
  exports.verifyConfig = function (conf) {
 | 
			
		||||
    if (!conf.NuhohSpec) {
 | 
			
		||||
@ -28,14 +28,18 @@
 | 
			
		||||
 | 
			
		||||
    if (!Array.isArray(conf.collections)) {
 | 
			
		||||
      if (conf.posts) {
 | 
			
		||||
        console.error("Please indent and nest 'posts' under the key 'collection' to continue");
 | 
			
		||||
        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");
 | 
			
		||||
        console.error(
 | 
			
		||||
          "Please indent and nest 'twitter' under the key 'themes' to continue"
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
      throw new Error("missing key 'themes'");
 | 
			
		||||
    }
 | 
			
		||||
@ -55,4 +59,4 @@
 | 
			
		||||
      throw new Error("missing key root");
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
}('undefined' !== typeof exports && exports || window));
 | 
			
		||||
})(("undefined" !== typeof exports && exports) || window);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										193
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							@ -0,0 +1,193 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "desirae",
 | 
			
		||||
  "version": "0.11.5",
 | 
			
		||||
  "lockfileVersion": 1,
 | 
			
		||||
  "requires": true,
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "argparse": {
 | 
			
		||||
      "version": "1.0.10",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
 | 
			
		||||
      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "sprintf-js": "~1.0.2"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "bluebird": {
 | 
			
		||||
      "version": "2.11.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz",
 | 
			
		||||
      "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE="
 | 
			
		||||
    },
 | 
			
		||||
    "crypto-rand": {
 | 
			
		||||
      "version": "0.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/crypto-rand/-/crypto-rand-0.0.2.tgz",
 | 
			
		||||
      "integrity": "sha1-Hn3CMQLhiRo+6zQPtwrElYCzLt0="
 | 
			
		||||
    },
 | 
			
		||||
    "escape-string-regexp": {
 | 
			
		||||
      "version": "1.0.5",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
 | 
			
		||||
      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
 | 
			
		||||
    },
 | 
			
		||||
    "esprima": {
 | 
			
		||||
      "version": "4.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
 | 
			
		||||
      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
 | 
			
		||||
    },
 | 
			
		||||
    "foreachasync": {
 | 
			
		||||
      "version": "5.1.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/foreachasync/-/foreachasync-5.1.3.tgz",
 | 
			
		||||
      "integrity": "sha512-q3/l5D2pyZG8aYe9xZQDAnS/KyP7QJakLUNrU/qGkd4bQUTzCUmvVFjagRggoxxjtb1ZrJB+jQeG4ojOLWkztw=="
 | 
			
		||||
    },
 | 
			
		||||
    "fs-extra": {
 | 
			
		||||
      "version": "0.6.4",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.6.4.tgz",
 | 
			
		||||
      "integrity": "sha1-9G8MdbeEH40gCzNIzU1pHVoJnRU=",
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "jsonfile": "~1.0.1",
 | 
			
		||||
        "mkdirp": "0.3.x",
 | 
			
		||||
        "ncp": "~0.4.2",
 | 
			
		||||
        "rimraf": "~2.2.0"
 | 
			
		||||
      },
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "mkdirp": {
 | 
			
		||||
          "version": "0.3.5",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz",
 | 
			
		||||
          "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc="
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "fs.extra": {
 | 
			
		||||
      "version": "1.3.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/fs.extra/-/fs.extra-1.3.2.tgz",
 | 
			
		||||
      "integrity": "sha1-3QI/kwE77iRTHxszUUw3sg/ZM0k=",
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "fs-extra": "~0.6.1",
 | 
			
		||||
        "mkdirp": "~0.3.5",
 | 
			
		||||
        "walk": "^2.3.9"
 | 
			
		||||
      },
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "mkdirp": {
 | 
			
		||||
          "version": "0.3.5",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz",
 | 
			
		||||
          "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc="
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "js-yaml": {
 | 
			
		||||
      "version": "3.14.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz",
 | 
			
		||||
      "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==",
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "argparse": "^1.0.7",
 | 
			
		||||
        "esprima": "^4.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "jsonfile": {
 | 
			
		||||
      "version": "1.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-1.0.1.tgz",
 | 
			
		||||
      "integrity": "sha1-6l7+QLg2kLmGZ2FKc5L8YOhCwN0="
 | 
			
		||||
    },
 | 
			
		||||
    "linkify-it": {
 | 
			
		||||
      "version": "0.1.5",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-0.1.5.tgz",
 | 
			
		||||
      "integrity": "sha1-OMWD0y+pPtcm2gDHrwAQeL+2uUU=",
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "uc.micro": "^1.0.0"
 | 
			
		||||
      },
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "uc.micro": {
 | 
			
		||||
          "version": "1.0.6",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
 | 
			
		||||
          "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "markdown-it": {
 | 
			
		||||
      "version": "3.1.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-3.1.0.tgz",
 | 
			
		||||
      "integrity": "sha1-IKcejmexKXyWrEfQD3tuaQ1uDDY=",
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "argparse": "~ 1.0.0",
 | 
			
		||||
        "linkify-it": "~ 0.1.2",
 | 
			
		||||
        "mdurl": "~ 1.0.0",
 | 
			
		||||
        "uc.micro": "~ 0.1.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "mdurl": {
 | 
			
		||||
      "version": "1.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
 | 
			
		||||
      "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4="
 | 
			
		||||
    },
 | 
			
		||||
    "minimist": {
 | 
			
		||||
      "version": "1.2.5",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
 | 
			
		||||
      "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
 | 
			
		||||
    },
 | 
			
		||||
    "mkdirp": {
 | 
			
		||||
      "version": "0.5.5",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
 | 
			
		||||
      "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "minimist": "^1.2.5"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "mustache": {
 | 
			
		||||
      "version": "2.3.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/mustache/-/mustache-2.3.2.tgz",
 | 
			
		||||
      "integrity": "sha512-KpMNwdQsYz3O/SBS1qJ/o3sqUJ5wSb8gb0pul8CO0S56b9Y2ALm8zCfsjPXsqGFfoNBkDwZuZIAjhsZI03gYVQ=="
 | 
			
		||||
    },
 | 
			
		||||
    "ncp": {
 | 
			
		||||
      "version": "0.4.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/ncp/-/ncp-0.4.2.tgz",
 | 
			
		||||
      "integrity": "sha1-q8xsvT7C7Spyn/bnwfqPAXhKhXQ="
 | 
			
		||||
    },
 | 
			
		||||
    "node-uuid": {
 | 
			
		||||
      "version": "1.4.8",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz",
 | 
			
		||||
      "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc="
 | 
			
		||||
    },
 | 
			
		||||
    "rimraf": {
 | 
			
		||||
      "version": "2.2.8",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz",
 | 
			
		||||
      "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI="
 | 
			
		||||
    },
 | 
			
		||||
    "secret-utils": {
 | 
			
		||||
      "version": "1.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/secret-utils/-/secret-utils-1.0.2.tgz",
 | 
			
		||||
      "integrity": "sha1-88GhRhCpTH+gMX3RVqj+AJgDb6c=",
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "crypto-rand": "0.0.2",
 | 
			
		||||
        "urlsafe-base64": "0.0.2"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "sprintf-js": {
 | 
			
		||||
      "version": "1.0.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
 | 
			
		||||
      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
 | 
			
		||||
    },
 | 
			
		||||
    "uc.micro": {
 | 
			
		||||
      "version": "0.1.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-0.1.0.tgz",
 | 
			
		||||
      "integrity": "sha1-7aESHR/blhVO1v3oJHu724MzCMo="
 | 
			
		||||
    },
 | 
			
		||||
    "urlsafe-base64": {
 | 
			
		||||
      "version": "0.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/urlsafe-base64/-/urlsafe-base64-0.0.2.tgz",
 | 
			
		||||
      "integrity": "sha1-+VqmedXqb86RQtY8tXCd4x7r7UI="
 | 
			
		||||
    },
 | 
			
		||||
    "walk": {
 | 
			
		||||
      "version": "2.3.14",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/walk/-/walk-2.3.14.tgz",
 | 
			
		||||
      "integrity": "sha512-5skcWAUmySj6hkBdH6B6+3ddMjVQYH5Qy9QGbPmN8kVmLteXk+yVXg+yfk1nbX30EYakahLrr8iPcCxJQSCBeg==",
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "foreachasync": "^3.0.0"
 | 
			
		||||
      },
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "foreachasync": {
 | 
			
		||||
          "version": "3.0.0",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/foreachasync/-/foreachasync-3.0.0.tgz",
 | 
			
		||||
          "integrity": "sha1-VQKYfchxS+M5IJfzLgBxyd7gfPY="
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -4,6 +4,7 @@
 | 
			
		||||
  "description": "An in-browser static blog library and static site generator. Similar to Jekyll, Octopress, Nanoc, etc",
 | 
			
		||||
  "main": "desirae.js",
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "prettier": "prettier --write './**/*.{js,css,html,json,md,py,xml}'",
 | 
			
		||||
    "test": "echo \"Error: no test specified\" && exit 1"
 | 
			
		||||
  },
 | 
			
		||||
  "repository": {
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
// http://ruhoh.com/docs/2/pages/#toc_41
 | 
			
		||||
/*
 | 
			
		||||
@ -6,32 +6,31 @@
 | 
			
		||||
  Otherwise it should use the the permalink for that collection.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
var tags
 | 
			
		||||
  , permalinkTransforms
 | 
			
		||||
  , cases
 | 
			
		||||
  , path    = /*exports.path ||*/ require('path')
 | 
			
		||||
  ;
 | 
			
		||||
  
 | 
			
		||||
var tags,
 | 
			
		||||
  permalinkTransforms,
 | 
			
		||||
  cases,
 | 
			
		||||
  path = /*exports.path ||*/ require("path");
 | 
			
		||||
tags = {
 | 
			
		||||
  year:           "Year from the page’s filename"
 | 
			
		||||
, month:          "Month from the page’s filename"
 | 
			
		||||
, day:            "Day from the page’s filename"
 | 
			
		||||
, path:           "The page file's path relative to the base of your website."
 | 
			
		||||
, relative_path:  "The page file's path relative to its name-spaced directory."
 | 
			
		||||
, filename:       "The page file's filename (path is not included)."
 | 
			
		||||
, categories:     "The specified categories for this page. If more than one category is set, only the first one is used. If no categories exist, the URL omits this parameter."
 | 
			
		||||
, i_month:        "Month from the page’s filename without leading zeros."
 | 
			
		||||
, i_day:          "Day from the page’s filename without leading zeros."
 | 
			
		||||
, title:          "The title, as a slug."
 | 
			
		||||
, slug:           "alias of title"
 | 
			
		||||
, name:           "alias of title"
 | 
			
		||||
, collection:     "i.e. posts/ or essays/ or whatever/"
 | 
			
		||||
  year: "Year from the page’s filename",
 | 
			
		||||
  month: "Month from the page’s filename",
 | 
			
		||||
  day: "Day from the page’s filename",
 | 
			
		||||
  path: "The page file's path relative to the base of your website.",
 | 
			
		||||
  relative_path: "The page file's path relative to its name-spaced directory.",
 | 
			
		||||
  filename: "The page file's filename (path is not included).",
 | 
			
		||||
  categories:
 | 
			
		||||
    "The specified categories for this page. If more than one category is set, only the first one is used. If no categories exist, the URL omits this parameter.",
 | 
			
		||||
  i_month: "Month from the page’s filename without leading zeros.",
 | 
			
		||||
  i_day: "Day from the page’s filename without leading zeros.",
 | 
			
		||||
  title: "The title, as a slug.",
 | 
			
		||||
  slug: "alias of title",
 | 
			
		||||
  name: "alias of title",
 | 
			
		||||
  collection: "i.e. posts/ or essays/ or whatever/",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function pad(str, n) {
 | 
			
		||||
  str = str.toString();
 | 
			
		||||
  if (str.length < n) {
 | 
			
		||||
    str = '0' + str;
 | 
			
		||||
    str = "0" + str;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return str;
 | 
			
		||||
@ -39,49 +38,51 @@ function pad(str, n) {
 | 
			
		||||
 | 
			
		||||
// https://www.youtube.com/watch?v=1NryFD9_hR0&list=RDOeLUK4a6Ojc&index=2
 | 
			
		||||
cases = {
 | 
			
		||||
  "/:title.html"                  : "/my-title.html"
 | 
			
		||||
, ":title/"                       : "/my-title/"
 | 
			
		||||
, "/:bad/:title/"                 : "/:bad/my-title/"
 | 
			
		||||
, "/:slug/"                       : "/my-title/"
 | 
			
		||||
, "/:path/:name.html"             : "/posts/fun/my-title.html"
 | 
			
		||||
, "/:relative_path/:name/"        : "/fun/my-title/"
 | 
			
		||||
, "/:year-:month-:day/:name"      : "/2015-07-04/my-title/"
 | 
			
		||||
, "/:year/:i_month/:i_day/:name"  : "/2015/7/4/my-title/"
 | 
			
		||||
, "/:filename.html"               : "/my-file-name.html"
 | 
			
		||||
, "/:filename"                    : "/my-file-name/"
 | 
			
		||||
, "/:filename/"                   : "/my-file-name/"
 | 
			
		||||
, "/:collection/:title/"          : "/posts/my-title/"
 | 
			
		||||
, "/:collection/:filename"        : "/posts/my-file-name/"
 | 
			
		||||
, "/:something/:or/:other"        : "/:something/:or/:other/"
 | 
			
		||||
, "/:categories/:title/"          : "/desi/my-title/"
 | 
			
		||||
  "/:title.html": "/my-title.html",
 | 
			
		||||
  ":title/": "/my-title/",
 | 
			
		||||
  "/:bad/:title/": "/:bad/my-title/",
 | 
			
		||||
  "/:slug/": "/my-title/",
 | 
			
		||||
  "/:path/:name.html": "/posts/fun/my-title.html",
 | 
			
		||||
  "/:relative_path/:name/": "/fun/my-title/",
 | 
			
		||||
  "/:year-:month-:day/:name": "/2015-07-04/my-title/",
 | 
			
		||||
  "/:year/:i_month/:i_day/:name": "/2015/7/4/my-title/",
 | 
			
		||||
  "/:filename.html": "/my-file-name.html",
 | 
			
		||||
  "/:filename": "/my-file-name/",
 | 
			
		||||
  "/:filename/": "/my-file-name/",
 | 
			
		||||
  "/:collection/:title/": "/posts/my-title/",
 | 
			
		||||
  "/:collection/:filename": "/posts/my-file-name/",
 | 
			
		||||
  "/:something/:or/:other": "/:something/:or/:other/",
 | 
			
		||||
  "/:categories/:title/": "/desi/my-title/",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Object.keys(cases).forEach(function (tpl) {
 | 
			
		||||
  var entity
 | 
			
		||||
    , tpld
 | 
			
		||||
    ;
 | 
			
		||||
  var entity, tpld;
 | 
			
		||||
 | 
			
		||||
  entity = {
 | 
			
		||||
    year          : '2015'
 | 
			
		||||
  , month         : '07'
 | 
			
		||||
  , day           : '04'
 | 
			
		||||
  , title         : "My Title"
 | 
			
		||||
  , slug          : "my-title"
 | 
			
		||||
  , name          : "My-File-Name.html"
 | 
			
		||||
  , relativePath  : "posts/fun"
 | 
			
		||||
  , path          : "posts/fun/My-File-Name.html"
 | 
			
		||||
  , collection    : "posts"
 | 
			
		||||
  , yml           : { categories: ['desi'] }
 | 
			
		||||
    year: "2015",
 | 
			
		||||
    month: "07",
 | 
			
		||||
    day: "04",
 | 
			
		||||
    title: "My Title",
 | 
			
		||||
    slug: "my-title",
 | 
			
		||||
    name: "My-File-Name.html",
 | 
			
		||||
    relativePath: "posts/fun",
 | 
			
		||||
    path: "posts/fun/My-File-Name.html",
 | 
			
		||||
    collection: "posts",
 | 
			
		||||
    yml: { categories: ["desi"] },
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  tpld = permalinker(tpl, entity);
 | 
			
		||||
 | 
			
		||||
  if (cases[tpl] !== tpld) {
 | 
			
		||||
    console.error('[ERROR]');
 | 
			
		||||
    console.error(tpl + ' ' + tpld + ' ' + cases[tpl]);
 | 
			
		||||
    console.error("[ERROR]");
 | 
			
		||||
    console.error(tpl + " " + tpld + " " + cases[tpl]);
 | 
			
		||||
    throw new Error(
 | 
			
		||||
      "Did not template permalink correctly. "
 | 
			
		||||
      + tpl + ' ' + tpld + ' ' + cases[tpl]
 | 
			
		||||
      "Did not template permalink correctly. " +
 | 
			
		||||
        tpl +
 | 
			
		||||
        " " +
 | 
			
		||||
        tpld +
 | 
			
		||||
        " " +
 | 
			
		||||
        cases[tpl]
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user