diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1 @@ +{} diff --git a/DATA.md b/DATA.md index 430ff7f..26b0c55 100644 --- a/DATA.md +++ b/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 diff --git a/ENTITY.md b/ENTITY.md index a161fe4..f1f0619 100644 --- a/ENTITY.md +++ b/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 diff --git a/GLOSSARY.md b/GLOSSARY.md index 3b0b4ca..65aa1b8 100644 --- a/GLOSSARY.md +++ b/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 diff --git a/README.md b/README.md index c5ddceb..ec95336 100644 --- a/README.md +++ b/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 . @@ -7,8 +6,7 @@ you should go to . 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/<>` 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/<>` 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" } } ``` diff --git a/TODO.md b/TODO.md index bce0e97..a41da94 100644 --- a/TODO.md +++ b/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 '' - } + return ( + '" + ); + }; } 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 diff --git a/bower.json b/bower.json index 4b75d79..66dd1fd 100644 --- a/bower.json +++ b/bower.json @@ -1,15 +1,10 @@ { "name": "desirae", "version": "0.11.2", - "authors": [ - "AJ ONeal " - ], + "authors": ["AJ ONeal "], "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", diff --git a/desirae.js b/desirae.js index eedbe49..27335f1 100644 --- a/desirae.js +++ b/desirae.js @@ -1,56 +1,54 @@ -;(function (exports) { - 'use strict'; +(function (exports) { + "use strict"; - var PromiseA = exports.Promise || require('bluebird').Promise - , path = exports.path || require('path') - , Mustache = exports.Mustache || require('mustache') - , forEachAsync = exports.forEachAsync || require('foreachasync').forEachAsync - , THEME_PREFIX = 'themes' + var PromiseA = exports.Promise || require("bluebird").Promise, + path = exports.path || require("path"), + Mustache = exports.Mustache || require("mustache"), + forEachAsync = exports.forEachAsync || require("foreachasync").forEachAsync, + THEME_PREFIX = "themes", //, sha1sum = exports.sha1sum || require('./lib/node-adaptors').sha1sum //, safeResolve = exports.safeResolve || require('./lib/utils').safeResolve //, UUID = exports.uuid || require('node-uuid') - , pforms - ; + pforms; - function Desi() { - } + function Desi() {} if (!exports.window) { - Desi.sha1sum = require('./lib/node-adapters').sha1sum; - Desi.fsapi = require('./lib/node-adapters').fsapi; - Desi.realFsapi = require('./lib/node-adapters').realFsapi; + Desi.sha1sum = require("./lib/node-adapters").sha1sum; + Desi.fsapi = require("./lib/node-adapters").fsapi; + Desi.realFsapi = require("./lib/node-adapters").realFsapi; // adds helper methods to fsapi - require('./lib/utils').create(Desi); + require("./lib/utils").create(Desi); // adds Desi.Frontmatter - require('./lib/frontmatter').create(Desi); + require("./lib/frontmatter").create(Desi); } Desi.slugify = function (title) { - return title.toLowerCase() - .replace(/["']/g, '') - .replace(/\W/g, '-') - .replace(/^-+/g, '') - .replace(/-+$/g, '') - .replace(/--/g, '-') - ; + return title + .toLowerCase() + .replace(/["']/g, "") + .replace(/\W/g, "-") + .replace(/^-+/g, "") + .replace(/-+$/g, "") + .replace(/--/g, "-"); }; Desi.slugifyPath = function (filepath) { // because not all filepaths are url-safe - return filepath.toLowerCase() - .replace(/\//g, '___SLASH___') - .replace(/["']/g, '') - .replace(/\W/g, '-') - .replace(/^-+/g, '') - .replace(/-+$/g, '') - .replace(/--/g, '-') - .replace(/___SLASH___/g, '/') - ; + return filepath + .toLowerCase() + .replace(/\//g, "___SLASH___") + .replace(/["']/g, "") + .replace(/\W/g, "-") + .replace(/^-+/g, "") + .replace(/-+$/g, "") + .replace(/--/g, "-") + .replace(/___SLASH___/g, "/"); }; Desi.pad = function (str, n, c) { - c = c || '0'; + c = c || "0"; if (0 !== n && !n) { n = 2; } @@ -64,117 +62,110 @@ }; Desi.firstCap = function (str) { - return str.replace(/^./, function ($1) { return $1.toUpperCase(); }); + return str.replace(/^./, function ($1) { + return $1.toUpperCase(); + }); }; // See https://github.com/janl/mustache.js/issues/415 Desi.num2str = function (obj) { - return JSON.parse(JSON.stringify(obj, function (key, val) { - if ('number' === typeof val) { - val = val.toString(); - } - return val; - })); + return JSON.parse( + JSON.stringify(obj, function (key, val) { + if ("number" === typeof val) { + val = val.toString(); + } + return val; + }) + ); }; pforms = { - year: function (entity) { - return entity.year; - } - , month: function (entity) { - return Desi.pad(entity.month, 2); - } - , day: function (entity) { - return Desi.pad(entity.day, 2); - } - , path: function (entity) { - return entity.relativePath - .toLowerCase() - .replace(/^\//, '') - ; - } - , relative_path: function (entity) { - // TODO slug the path in desirae proper? - // TODO remove collection from start of path instead - // of blindly assuming one directory at start of path - // entity.collection.name - return entity.relativePath - .toLowerCase() - .replace(/^\/?[^\/]+\//, '') - ; - } - , filename: function (entity) { - // don't put .html - return entity.name - .toLowerCase() - .replace(/\.\w+$/, '') - ; - } - , slug: function (entity) { - // alias of title - return entity.slug; - } - , title: function (entity) { - return entity.slug; - } - , name: function (entity) { - // alias of title - return entity.slug; - } - , collection: function (entity) { - // TODO implement in desirae - return entity.collection && entity.collection.name - || entity.collectionname - || entity.collection - || '' - ; - } - , categories: function (entity) { - return (entity.categories)[0]||''; - } - , i_month: function (entity) { - return parseInt(entity.month, 10) || 0; - } - , i_day: function (entity) { - return parseInt(entity.day, 10) || 0; - } + year: function (entity) { + return entity.year; + }, + month: function (entity) { + return Desi.pad(entity.month, 2); + }, + day: function (entity) { + return Desi.pad(entity.day, 2); + }, + path: function (entity) { + return entity.relativePath.toLowerCase().replace(/^\//, ""); + }, + relative_path: function (entity) { + // TODO slug the path in desirae proper? + // TODO remove collection from start of path instead + // of blindly assuming one directory at start of path + // entity.collection.name + return entity.relativePath.toLowerCase().replace(/^\/?[^\/]+\//, ""); + }, + filename: function (entity) { + // don't put .html + return entity.name.toLowerCase().replace(/\.\w+$/, ""); + }, + slug: function (entity) { + // alias of title + return entity.slug; + }, + title: function (entity) { + return entity.slug; + }, + name: function (entity) { + // alias of title + return entity.slug; + }, + collection: function (entity) { + // TODO implement in desirae + return ( + (entity.collection && entity.collection.name) || + entity.collectionname || + entity.collection || + "" + ); + }, + categories: function (entity) { + return entity.categories[0] || ""; + }, + i_month: function (entity) { + return parseInt(entity.month, 10) || 0; + }, + i_day: function (entity) { + return parseInt(entity.day, 10) || 0; + }, }; Desi.permalinkify = function (desi, purl, entity) { - var parts = purl.split('/') - ; - + var parts = purl.split("/"); // when created from the web or cmd the file doesn't yet exist if (!entity.name) { - entity.name = entity.slug + '.html'; + entity.name = entity.slug + ".html"; } if (!entity.relativePath) { - entity.relativePath = entity.collection || Object.keys(desi.config.collections)[0] || 'posts'; + entity.relativePath = + entity.collection || Object.keys(desi.config.collections)[0] || "posts"; } parts.forEach(function (part, i) { - var re = /:(\w+)/g - , m - // needs to be a copy, not a reference - , opart = part.toString() - ; - + var re = /:(\w+)/g, + m, + // needs to be a copy, not a reference + opart = part.toString(); /* jshint -W084 */ while (null !== (m = re.exec(opart))) { if (pforms[m[1]]) { - part = part.replace(':' + m[1], pforms[m[1]](entity)); + part = part.replace(":" + m[1], pforms[m[1]](entity)); } } /* jshint +W084 */ - parts[i] = part || ''; + parts[i] = part || ""; }); - parts.unshift('/'); + parts.unshift("/"); purl = path.join.apply(null, parts); if (!/(\/|\.html?)$/.test(purl)) { // we just default to a slash if you were ambiguous - purl += '/'; + purl += "/"; } return purl; @@ -182,9 +173,7 @@ function readFrontmatter(things) { return forEachAsync(things, function (file) { - var parts = Desi.Frontmatter.parse(file.contents) - ; - + var parts = Desi.Frontmatter.parse(file.contents); if (!file.sha1) { // TODO sha1sum } @@ -197,21 +186,15 @@ // TODO redo entirely function getDirty(cacheByPath, cacheBySha1, thingies, deps) { - var byDirty = {} - ; - + var byDirty = {}; Object.keys(thingies).forEach(function (key) { - var files = thingies[key] - , cached - , cdate - , fdate - ; + var files = thingies[key], + cached, + cdate, + fdate; files.forEach(function (file) { - var pathname = path.join(file.relativePath + '/' + file.name) - ; - - + var pathname = path.join(file.relativePath + "/" + file.name); // TODO legitimately checkout layout dependencies if (deps && Object.keys(deps).length) { byDirty[pathname] = file; @@ -243,7 +226,6 @@ byDirty[pathname] = file; } } - }); }); @@ -252,17 +234,26 @@ function getLayout(desi, themename, layoutname, arr, i) { if (i > (desi.config.max_layouth_depth || 10)) { - console.error('desi.config.yml:max_layouth_depth if your layouts intentionally nest more than ' + i + ' levels deep'); - throw new Error("Possible circular dependency in theme '" + themename + "', layout '" + layoutname + "'"); + console.error( + "desi.config.yml:max_layouth_depth if your layouts intentionally nest more than " + + i + + " levels deep" + ); + throw new Error( + "Possible circular dependency in theme '" + + themename + + "', layout '" + + layoutname + + "'" + ); } i = i || 0; // TODO meta.layout for each entity arr = arr || []; - var layoutdir = 'layouts' - , themepath - , file - ; + var layoutdir = "layouts", + themepath, + file; if (!themename) { themename = desi.site.theme || desi.config.theme; @@ -273,22 +264,21 @@ } // TODO NO DEFAULTS - if ('__page__' === layoutname) { - layoutname = desi.config.themes[themename].pageLayout || 'page'; - } else if ('__post__' === layoutname) { - layoutname = desi.config.themes[themename].postLayout || 'post'; + if ("__page__" === layoutname) { + layoutname = desi.config.themes[themename].pageLayout || "page"; + } else if ("__post__" === layoutname) { + layoutname = desi.config.themes[themename].postLayout || "post"; } else if (!layoutname) { // TODO assign __post__ in a previous step and do away with this case - layoutname = desi.config.themes[themename].postLayout || 'post'; + layoutname = desi.config.themes[themename].postLayout || "post"; } - // THEME PREFIX themepath = path.join(THEME_PREFIX, themename, layoutdir, layoutname); desi.content.themes.some(function (theme) { // TODO what if it isn't html? - if (theme.path === themepath || theme.path.match(themepath + '\\.html')) { + if (theme.path === themepath || theme.path.match(themepath + "\\.html")) { file = theme; theme.ext = path.extname(file.path); // TODO merge with yml? @@ -321,46 +311,55 @@ /* function clone(obj) { return JSON.parse(JSON.stringify(obj)); } */ Desi.YAML = { - parse: (exports.jsyaml || require('js-yaml')).load - , stringify: (exports.jsyaml || require('js-yaml')).dump + parse: (exports.jsyaml || require("js-yaml")).load, + stringify: (exports.jsyaml || require("js-yaml")).dump, }; Desi.toDesiDate = Desi.toLocaleDate = function (d) { - return d.getFullYear() + '-' + Desi.pad(d.getMonth() + 1) + '-' + Desi.pad(d.getDate()) - + ' ' - + (d.getHours() % 12) + ':' + Desi.pad(d.getMinutes()) + ' ' + (d.getHours() - 12 >= 0 ? 'pm' : 'am') - ; + return ( + d.getFullYear() + + "-" + + Desi.pad(d.getMonth() + 1) + + "-" + + Desi.pad(d.getDate()) + + " " + + (d.getHours() % 12) + + ":" + + Desi.pad(d.getMinutes()) + + " " + + (d.getHours() - 12 >= 0 ? "pm" : "am") + ); }; Desi.fromLocaleDate = function (str) { // handles ISO and ISO-ish dates - var m = str.match(/(\d\d\d\d)-(\d{1,2})-(\d{1,2})([T\s](\d{1,2}):(\d{1,2})(:(\d{1,2}))?)?/) - , d = {} - ; - + var m = str.match( + /(\d\d\d\d)-(\d{1,2})-(\d{1,2})([T\s](\d{1,2}):(\d{1,2})(:(\d{1,2}))?)?/ + ), + d = {}; if (!m) { return []; } - d.year = m[1]; - d.month = m[2]; - d.day = m[3]; + d.year = m[1]; + d.month = m[2]; + d.day = m[3]; - d.hour = m[4] = Desi.pad(m[5] || '00'); // hours - d.minute = m[5] = Desi.pad(m[6] || '00'); // minutes - d.second = m[6] = Desi.pad(m[8] || '00'); // seconds + d.hour = m[4] = Desi.pad(m[5] || "00"); // hours + d.minute = m[5] = Desi.pad(m[6] || "00"); // minutes + d.second = m[6] = Desi.pad(m[8] || "00"); // seconds if (parseInt(m[4], 10) > 12) { - d.twelve_hour = m[7] = m[4] - 12; // 12-hour - d.meridian = m[8] = 'pm'; // am/pm + d.twelve_hour = m[7] = m[4] - 12; // 12-hour + d.meridian = m[8] = "pm"; // am/pm } else { d.twelve_hour = m[7] = m[4]; - d.meridian = m[8] = 'am'; + d.meridian = m[8] = "am"; } // 0 -> 12 if (!parseInt(d.twelve_hour, 10)) { - d.twelve_hour = '12'; + d.twelve_hour = "12"; } return d; @@ -385,28 +384,27 @@ // config.yml, data.yml, site.yml, authors return PromiseA.all([ - Desi.fsapi.getAllConfigFiles() - /*, fsapi.getBlogdir()*/ - ]).then(function (plop) { - var arr = plop[0] + Desi.fsapi.getAllConfigFiles(), + /*, fsapi.getBlogdir()*/ + ]) + .then(function (plop) { + var arr = plop[0]; //, blogdir = plop[1] - ; + //desi.blogdir = blogdir; + //desi.originals = {}; + //desi.copies = {}; - //desi.blogdir = blogdir; - //desi.originals = {}; - //desi.copies = {}; + Object.keys(arr).forEach(function (key) { + desi[key] = arr[key]; + //desi.originals[key] = arr[key]; + //desi.copies[key] = clone(arr[key]); + //desi[key] = clone(arr[key]); + }); - Object.keys(arr).forEach(function (key) { - desi[key] = arr[key]; - //desi.originals[key] = arr[key]; - //desi.copies[key] = clone(arr[key]); - //desi[key] = clone(arr[key]); - }); - - // TODO just walk all of ./*.yml authors, posts, themes, _root from the get-go - desi.config.rootdir = desi.config.rootdir || '_root'; - // TODO create a config linter as a separate module - /* + // TODO just walk all of ./*.yml authors, posts, themes, _root from the get-go + desi.config.rootdir = desi.config.rootdir || "_root"; + // TODO create a config linter as a separate module + /* if ('object' !== typeof desi.config.collections || !Object.keys(desi.config.collections).length) { desi.config.collections = { 'posts': {} }; } @@ -421,125 +419,120 @@ desi.site.theme = 'ruhoh-twitter'; } */ - if (!Array.isArray(desi.site.navigation) || !desi.site.navigation.length) { - desi.site.navigation = []; // ['archive']; - } + if ( + !Array.isArray(desi.site.navigation) || + !desi.site.navigation.length + ) { + desi.site.navigation = []; // ['archive']; + } - var collectionnames = Object.keys(desi.config.collections) - , themenames = Object.keys(desi.config.themes) - .filter(function (k) { return 'default' !== k; }) - //.map(function (n) { return path.join(n, 'layouts'); }) - , assetnames = Object.keys(desi.config.assets) - ; - - // TODO make document configurability - return PromiseA.all([ - Desi.fsapi.getMeta( - themenames.map(function (n) { return path.join(THEME_PREFIX, n); }) - , { dotfiles: false - , extensions: Object.keys(Desi._exts.themes) - } - ) - , Desi.fsapi.getMeta( - [desi.config.rootdir] - , { dotfiles: false - , extensions: Object.keys(Desi._exts.collections) - } - ) - , Desi.fsapi.getMeta( - collectionnames - , { dotfiles: false - , extensions: Object.keys(Desi._exts.collections) - } - ) - , Desi.fsapi.getMeta( - assetnames - , { dotfiles: false - //, extensions: Object.keys(Desi._exts.assets) - } - ) - , Desi.fsapi.getCache() - ]); - }).then(function (things) { - - function noErrors(map) { - Object.keys(map).forEach(function (pathname) { - map[pathname] = map[pathname].filter(function (metaf) { - if (!metaf.relativePath) { - metaf.relativePath = path.dirname(metaf.path); - metaf.name = metaf.name || path.basename(metaf.path); + var collectionnames = Object.keys(desi.config.collections), + themenames = Object.keys(desi.config.themes).filter(function (k) { + return "default" !== k; + }), + //.map(function (n) { return path.join(n, 'layouts'); }) + assetnames = Object.keys(desi.config.assets); + // TODO make document configurability + return PromiseA.all([ + Desi.fsapi.getMeta( + themenames.map(function (n) { + return path.join(THEME_PREFIX, n); + }), + { + dotfiles: false, + extensions: Object.keys(Desi._exts.themes), } + ), + Desi.fsapi.getMeta([desi.config.rootdir], { + dotfiles: false, + extensions: Object.keys(Desi._exts.collections), + }), + Desi.fsapi.getMeta(collectionnames, { + dotfiles: false, + extensions: Object.keys(Desi._exts.collections), + }), + Desi.fsapi.getMeta(assetnames, { + dotfiles: false, + //, extensions: Object.keys(Desi._exts.assets) + }), + Desi.fsapi.getCache(), + ]); + }) + .then(function (things) { + function noErrors(map) { + Object.keys(map).forEach(function (pathname) { + map[pathname] = map[pathname].filter(function (metaf) { + if (!metaf.relativePath) { + metaf.relativePath = path.dirname(metaf.path); + metaf.name = metaf.name || path.basename(metaf.path); + } - metaf.path = path.join(metaf.relativePath, metaf.name); + metaf.path = path.join(metaf.relativePath, metaf.name); + if (metaf.error) { + console.error("Couldn't read '" + metaf.path + "'"); + console.error(metaf.error); + throw new Error(metaf.error); + //return false; + } - if (metaf.error) { - console.error("Couldn't read '" + metaf.path + "'"); - console.error(metaf.error); - throw new Error(metaf.error); - //return false; - } + if (!metaf.size) { + console.error("Junk file (0 bytes) '" + metaf.path + "'"); + console.error(metaf.error); + throw new Error(metaf.error); + //return false; + } - if (!metaf.size) { - console.error("Junk file (0 bytes) '" + metaf.path + "'"); - console.error(metaf.error); - throw new Error(metaf.error); - //return false; - } - - return true; + return true; + }); }); - }); - return map; - } + return map; + } - var themes = noErrors(things[0]) - , root = noErrors(things[1])[desi.config.rootdir] - , collections = noErrors(things[2]) - , assets = noErrors(things[3]) - , cache = noErrors(things[4]) - ; + var themes = noErrors(things[0]), + root = noErrors(things[1])[desi.config.rootdir], + collections = noErrors(things[2]), + assets = noErrors(things[3]), + cache = noErrors(things[4]); + if (!themes[Object.keys(themes)[0]].length) { + console.error("Missing THEMES!"); + throw new Error("It seems that your themes directory is missing"); + } - if (!themes[Object.keys(themes)[0]].length) { - console.error('Missing THEMES!'); - throw new Error('It seems that your themes directory is missing'); - } + if (!root.length) { + console.error("Missing ROOT!"); + throw new Error("It seems that your root directory is missing"); + } - if (!root.length) { - console.error('Missing ROOT!'); - throw new Error('It seems that your root directory is missing'); - } - - /* + /* if (!collections[Object.keys(collections)[0]].length) { console.error('Missing Collections!'); throw new Error('It seems that your collections are missing'); } */ - desi.cache = cache; - desi.meta = { - themes: themes - , collections: collections - , root: root - , assets: assets - }; - desi.styles = []; + desi.cache = cache; + desi.meta = { + themes: themes, + collections: collections, + root: root, + assets: assets, + }; + desi.styles = []; - return desi; - }); + return desi; + }); }; Desi.getDirtyFiles = function (desi, env) { - var cache = desi.cache + var cache = desi.cache, //, config = desi.config - , cacheByPath = {} - , cacheBySha1 = {} - , dfiles - , dthemes - , droot - ; + cacheByPath = {}, + cacheBySha1 = {}, + dfiles, + dthemes, + droot; cache.sources = cache.sources || []; cache.sources.forEach(function (source) { @@ -552,13 +545,17 @@ dfiles = getDirty(cacheByPath, cacheBySha1, desi.meta.collections, dthemes); return PromiseA.all([ - Object.keys(droot).length ? Desi.fsapi.getContents(Object.keys(droot)) : PromiseA.resolve([]) - , Object.keys(dfiles).length ? Desi.fsapi.getContents(Object.keys(dfiles)) : PromiseA.resolve([]) - , Object.keys(dthemes).length ? Desi.fsapi.getContents(Object.keys(dthemes)) : PromiseA.resolve([]) + Object.keys(droot).length + ? Desi.fsapi.getContents(Object.keys(droot)) + : PromiseA.resolve([]), + Object.keys(dfiles).length + ? Desi.fsapi.getContents(Object.keys(dfiles)) + : PromiseA.resolve([]), + Object.keys(dthemes).length + ? Desi.fsapi.getContents(Object.keys(dthemes)) + : PromiseA.resolve([]), ]).then(function (arr) { - var result = { root: [], collections: [], themes: [] } - ; - + var result = { root: [], collections: [], themes: [] }; function noErrors(collectionBase, arr, entity) { // FOO FOO FOO if (!entity.error) { @@ -567,24 +564,24 @@ entity.name = entity.name || path.basename(entity.path); } - entity.relativePath = entity.relativePath.replace(desi.config.rootdir, '').replace(/^\//, ''); + entity.relativePath = entity.relativePath + .replace(desi.config.rootdir, "") + .replace(/^\//, ""); entity.path = path.join(entity.relativePath, entity.name); entity.ext = path.extname(entity.path); // TODO better collection detection - if ('root' === collectionBase) { + if ("root" === collectionBase) { // TODO how to reconcile rootdir vs _root vs root? - entity.collection = 'root'; - entity.collectionType = 'root'; + entity.collection = "root"; + entity.collectionType = "root"; // desi.config.rootdir; - } - else if ('collections' === collectionBase) { - entity.collection = entity.relativePath.split('/')[0]; - entity.collectionType = 'collections'; - } - else if ('themes' === collectionBase) { - entity.collection = entity.relativePath.split('/')[1]; - entity.collectionType = 'themes'; + } else if ("collections" === collectionBase) { + entity.collection = entity.relativePath.split("/")[0]; + entity.collectionType = "collections"; + } else if ("themes" === collectionBase) { + entity.collection = entity.relativePath.split("/")[1]; + entity.collectionType = "themes"; } arr.push(entity); @@ -601,64 +598,74 @@ } return forEachAsync(arr[0], function (o) { - return noErrors('root', result.root, o); - }).then(function () { - return forEachAsync(arr[1], function (o) { - return noErrors('collections', result.collections, o); - }); - }).then(function () { - return forEachAsync(arr[2], function (o) { - return noErrors('themes', result.themes, o); - }); - }).then(function () { - desi.content = result; + return noErrors("root", result.root, o); + }) + .then(function () { + return forEachAsync(arr[1], function (o) { + return noErrors("collections", result.collections, o); + }); + }) + .then(function () { + return forEachAsync(arr[2], function (o) { + return noErrors("themes", result.themes, o); + }); + }) + .then(function () { + desi.content = result; - return desi; - }); + return desi; + }); }); }; - Desi.copyAssets = function(desi, env) { - var files = {} - ; - + Desi.copyAssets = function (desi, env) { + var files = {}; Object.keys(desi.meta.assets).forEach(function (key) { - var assets = desi.meta.assets[key] - ; - + var assets = desi.meta.assets[key]; assets.forEach(function (asset) { - files[path.join(asset.relativePath, asset.name)] = path.join(env.compiled_path, 'assets', asset.relativePath, asset.name); + files[path.join(asset.relativePath, asset.name)] = path.join( + env.compiled_path, + "assets", + asset.relativePath, + asset.name + ); }); }); - return (Object.keys(files).length && Desi.fsapi.copy(files).then(function (copied) { - if (copied.error) { - console.error(copied.error); - throw new Error(copied.error); - } + return ( + (Object.keys(files).length && + Desi.fsapi.copy(files).then(function (copied) { + if (copied.error) { + console.error(copied.error); + throw new Error(copied.error); + } - if (copied.errors && copied.errors.length) { - console.error("Errors copying assets..."); - copied.errors.forEach(function (err) { - console.error(err); - throw new Error(err); - }); - } + if (copied.errors && copied.errors.length) { + console.error("Errors copying assets..."); + copied.errors.forEach(function (err) { + console.error(err); + throw new Error(err); + }); + } - return desi; - }) || PromiseA.resolve(desi)); + return desi; + })) || + PromiseA.resolve(desi) + ); }; Desi.parseFrontmatter = function (desi) { - return readFrontmatter(desi.content.root.concat(desi.content.themes.concat(desi.content.collections))).then(function () { + return readFrontmatter( + desi.content.root.concat( + desi.content.themes.concat(desi.content.collections) + ) + ).then(function () { return desi; }); }; Desi.getNav = function (desi) { - var alwaysAdd = true - ; - + var alwaysAdd = true; if (desi.site.navigation.length) { alwaysAdd = false; } @@ -667,16 +674,18 @@ desi.navigation = []; desi.content.root.forEach(function (entity) { - var name = path.join(entity.relativePath, path.basename(entity.name, path.extname(entity.name))) - , nindex - ; + var name = path.join( + entity.relativePath, + path.basename(entity.name, path.extname(entity.name)) + ), + nindex; // The index should not show up in the automatic listing - if (alwaysAdd && 'index' === name) { + if (alwaysAdd && "index" === name) { return; } - nindex = (desi.site.navigation).indexOf(name); + nindex = desi.site.navigation.indexOf(name); if (!alwaysAdd && -1 === nindex) { return; } else { @@ -685,9 +694,9 @@ // TODO this happens before normalization... should fix that... desi.navigation[nindex] = { - title: entity.yml && entity.yml.title || Desi.firstCap(name) - , name: name - , active: false // placeholder + title: (entity.yml && entity.yml.title) || Desi.firstCap(name), + name: name, + active: false, // placeholder }; }); @@ -704,12 +713,11 @@ function makeTransformer(type) { return function (entity, i, entities) { - var collection - ; + var collection; - if ('root' === type) { + if ("root" === type) { // TODO 'no magic', 'defaults in the app, not the lib' - collection = { permalink: '/:filename/' }; + collection = { permalink: "/:filename/" }; } else { collection = desi.config[type][entity.collection]; } @@ -717,9 +725,11 @@ Desi._transformers[type].forEach(function (obj) { try { obj.transform(desi, env, collection, entity, i, entities); - } catch(e) { - console.error('[ERROR]'); - console.error("Transform " + obj.name + " failed on " + entity.path); + } catch (e) { + console.error("[ERROR]"); + console.error( + "Transform " + obj.name + " failed on " + entity.path + ); console.error(e.message); throw e; } @@ -727,8 +737,8 @@ }; } - desi.content.root.forEach(makeTransformer('root')); - desi.content.collections.forEach(makeTransformer('collections')); + desi.content.root.forEach(makeTransformer("root")); + desi.content.collections.forEach(makeTransformer("collections")); return PromiseA.resolve(desi); }; @@ -737,7 +747,7 @@ Desi.registerAggregator = function (fn) { Desi._aggregations.push(fn); }; - Desi.runAggregations = function (desi, env/*, collectionname*/) { + Desi.runAggregations = function (desi, env /*, collectionname*/) { return forEachAsync(Desi._aggregations, function (fn) { return fn(desi, env); }).then(function () { @@ -750,34 +760,42 @@ if (!Desi._datamaps[name]) { Desi._datamaps[name] = fn; } else { - throw new Error("cannot add additional data mapper for '" - + name + "' (there's already one assigned)"); + throw new Error( + "cannot add additional data mapper for '" + + name + + "' (there's already one assigned)" + ); } }; Desi._transformers = { root: [], collections: [], assets: [], themes: [] }; Desi.registerTransform = function (name, fn, opts) { - ['root', 'collections', 'themes', 'assets'].forEach(function (thingname) { + ["root", "collections", "themes", "assets"].forEach(function (thingname) { if (!opts[thingname]) { return; } - if (Desi._transformers[thingname].some(function (obj) { - if (name === obj.name || fn === obj.transform) { - return true; - } - })) { - throw new Error("cannot add additional transformer for '" - + name + "' (there's already one assigned)"); + if ( + Desi._transformers[thingname].some(function (obj) { + if (name === obj.name || fn === obj.transform) { + return true; + } + }) + ) { + throw new Error( + "cannot add additional transformer for '" + + name + + "' (there's already one assigned)" + ); } Desi._transformers[thingname].push({ - name: name - , transform: fn - , root: opts.root - , assets: opts.assets - , themes: opts.themes - , collections: opts.collections + name: name, + transform: fn, + root: opts.root, + assets: opts.assets, + themes: opts.themes, + collections: opts.collections, }); }); }; @@ -785,18 +803,18 @@ Desi._exts = { root: {}, collections: {}, assets: {}, themes: {} }; Desi._renderers = { root: {}, collections: {}, assets: {}, themes: {} }; - Desi.registerRenderer = function(ext, fn, opts) { + Desi.registerRenderer = function (ext, fn, opts) { opts = opts || {}; - if (!('root' in opts)) { + if (!("root" in opts)) { opts.root = true; } - if (!('collections' in opts)) { + if (!("collections" in opts)) { opts.collections = true; } - ext = ext.replace(/^\./, ''); + ext = ext.replace(/^\./, ""); - ['root', 'collections', 'themes', 'assets'].forEach(function (key) { + ["root", "collections", "themes", "assets"].forEach(function (key) { if (!opts[key]) { return; } @@ -811,70 +829,74 @@ }); }; Desi.render = function (ext, content, view) { - var type = view.entity.collectionType - ; - - ext = (ext||'').toLowerCase().replace(/^\./, ''); + var type = view.entity.collectionType; + ext = (ext || "").toLowerCase().replace(/^\./, ""); if (Desi._renderers[type][ext] && Desi._renderers[type][ext].length) { return Desi._renderers[type][ext][0](content, view); } - return PromiseA.reject(new Error("no '" + type + "' renderer registered for '." + ext + "'")); + return PromiseA.reject( + new Error("no '" + type + "' renderer registered for '." + ext + "'") + ); }; function renderLayers(desi, env, view, entity) { - var mustached = '' - , layers - ; + var mustached = "", + layers; // BUG XXX the entity doesn't get a datamap (though it probably doesn't need one) layers = getLayout(desi, entity.theme, entity.layout, [entity]); return forEachAsync(layers, function (current) { - var body = (current.body || current.contents || '').trim() - ; + var body = (current.body || current.contents || "").trim(); + return Desi.render(current.ext, body, view) + .then(function (html) { + // TODO organize datamap inheritence + var datamap = + Desi._datamaps[current.config && current.datamap] || + Desi._datamaps[env.datamap] || + Desi._datamaps[entity.datamap] || + Desi._datamaps["ruhoh@2.6"], + newview; - return Desi.render(current.ext, body, view).then(function (html) { - // TODO organize datamap inheritence - var datamap = Desi._datamaps[current.config && current.datamap] - || Desi._datamaps[env.datamap] - || Desi._datamaps[entity.datamap] - || Desi._datamaps['ruhoh@2.6'] - , newview - ; + view.contents = mustached; - view.contents = mustached; + // shallowClone to prevent perfect object equality (and potential template caching) + view.entity.original_base_path = view.entity.base_path; + view.entity.home_path = view.entity.base_path + "/index.html"; + env.original_base_path = env.base_path; + if (env.explicitIndexes) { + view.entity.base_path = path.join( + view.entity.base_path, + "index.html" + ); + env.base_path = path.join(env.base_path, "index.html"); + } + newview = datamap(view); + env.base_path = env.original_base_path; + view.entity.base_path = view.entity.original_base_path; + mustached = Mustache.render(html, newview, desi.partials); - // shallowClone to prevent perfect object equality (and potential template caching) - view.entity.original_base_path = view.entity.base_path; - view.entity.home_path = view.entity.base_path + '/index.html'; - env.original_base_path = env.base_path; - if (env.explicitIndexes) { - view.entity.base_path = path.join(view.entity.base_path, 'index.html'); - env.base_path = path.join(env.base_path, 'index.html'); - } - newview = datamap(view); - env.base_path = env.original_base_path; - view.entity.base_path = view.entity.original_base_path; - mustached = Mustache.render(html, newview, desi.partials); - - return mustached; - }).catch(function (e) { - console.error(current); - if (env.onError) { - return env.onError(e); - } else { - console.error('no registered renderer for ' + entity.path + ' or rendering failed'); - throw e; - } - }); + return mustached; + }) + .catch(function (e) { + console.error(current); + if (env.onError) { + return env.onError(e); + } else { + console.error( + "no registered renderer for " + + entity.path + + " or rendering failed" + ); + throw e; + } + }); }); } Desi.build = function (desi, env) { - var compiled = [] - ; - + var compiled = []; if (/dropbox/.test(env.base_url)) { env.explicitIndexes = true; } @@ -884,31 +906,44 @@ } */ function compileThemeEntity(entity, i, arr) { - var view - ; + var view; - console.info("[themes] compiling " + (i + 1) + "/" + arr.length + " " + entity.path); + console.info( + "[themes] compiling " + (i + 1) + "/" + arr.length + " " + entity.path + ); // TODO generate per-page for a more full 'view' object? - view = { entity: { collectionType: 'themes' }, url: path.join(env.base_path, entity.path) }; + view = { + entity: { collectionType: "themes" }, + url: path.join(env.base_path, entity.path), + }; // TODO this is more 'preprocessing' than 'rendering', perse - return Desi.render(entity.ext, entity.body || entity.contents, view).then(function (css) { - compiled.push({ contents: css, path: entity.path }); - // TODO read theme config - if (/stylesheets.*\.css/.test(entity.path) && (!/google/.test(entity.path) || /obsid/.test(entity.path))) { - desi.styles.push(Mustache.render(desi.partials.stylesheet_link, view)); + return Desi.render(entity.ext, entity.body || entity.contents, view).then( + function (css) { + compiled.push({ contents: css, path: entity.path }); + // TODO read theme config + if ( + /stylesheets.*\.css/.test(entity.path) && + (!/google/.test(entity.path) || /obsid/.test(entity.path)) + ) { + desi.styles.push( + Mustache.render(desi.partials.stylesheet_link, view) + ); + } } - }); + ); } function compileContentEntity(entity, i, arr) { - console.info("compiling " + (i + 1) + "/" + arr.length + " " + entity.path); - - var navigation = JSON.parse(JSON.stringify(desi.navigation)) - , author = desi.authors[entity.yml.author] || desi.authors[Object.keys(desi.authors)[0]] - , view - , themename = entity.theme || desi.site.theme - ; + console.info( + "compiling " + (i + 1) + "/" + arr.length + " " + entity.path + ); + var navigation = JSON.parse(JSON.stringify(desi.navigation)), + author = + desi.authors[entity.yml.author] || + desi.authors[Object.keys(desi.authors)[0]], + view, + themename = entity.theme || desi.site.theme; if (!author) { console.error("\n\n\n"); console.error("You don't have any files in authors/*.yml"); @@ -931,99 +966,112 @@ if (!/\.x?html?$/.test(nav.href)) { // add trailing slash - nav.href += '/'; + nav.href += "/"; } - if (nav.href.replace(/(\/)?(\/index)?(\.html)?$/i, '') - === entity.relative_url.replace(/(\/)?(\/index)?(\.html)?$/i, '')) { + if ( + nav.href.replace(/(\/)?(\/index)?(\.html)?$/i, "") === + entity.relative_url.replace(/(\/)?(\/index)?(\.html)?$/i, "") + ) { nav.active = true; } if (env.explicitIndexes && !/\.x?html?$/.test(nav.href)) { - nav.href = path.join(nav.href, 'index.html'); + nav.href = path.join(nav.href, "index.html"); } nav.path = nav.href; }); view = { - env: env - , config: desi.config - , site: desi.site - , data: desi.data - , entity: entity - , entity_index: i - , entities: arr - , desi: desi - , navigation: navigation - , author: Desi.num2str(author) + env: env, + config: desi.config, + site: desi.site, + data: desi.data, + entity: entity, + entity_index: i, + entities: arr, + desi: desi, + navigation: navigation, + author: Desi.num2str(author), }; desi.allStyles = desi.styles.slice(0); desi.styles = desi.styles.filter(function (str) { // TODO better matching - return str.match('/' + themename + '/'); + return str.match("/" + themename + "/"); }); - return renderLayers(desi, env, view, entity).then(function (html) { - desi.styles = desi.allStyles; - // NOTE: by now, all permalinks should be in the format - // /path/to/page.html or /path/to/page/index.html - if (/^(index)?(\/?index.html)?$/.test(entity.permalink)) { - console.info("[index] compiling " + (entity.path || entity.name)); - compiled.push({ contents: html, path: path.join('index.html') }); - } else { - //console.info("[collection] compiling " + entity.path, entity.relative_file); - compiled.push({ contents: html, path: path.join(entity.relative_file.replace(env.base_path, '')) }); - } + return renderLayers(desi, env, view, entity) + .then(function (html) { + desi.styles = desi.allStyles; + // NOTE: by now, all permalinks should be in the format + // /path/to/page.html or /path/to/page/index.html + if (/^(index)?(\/?index.html)?$/.test(entity.permalink)) { + console.info("[index] compiling " + (entity.path || entity.name)); + compiled.push({ + contents: html, + path: path.join("index.html"), + }); + } else { + //console.info("[collection] compiling " + entity.path, entity.relative_file); + compiled.push({ + contents: html, + path: path.join(entity.relative_file.replace(env.base_path, "")), + }); + } - // catches /a, /a/index.html, a/index.html - // but not index.html /index.html - if (/^.+\/(index\.x?html?)$/.test(entity.permalink)) { - entity.redirects.push(entity.permalink.replace(/\/(index.x?html?)?$/, '.html')); - } else if (/\.x?html?$/.test(entity.permalink)) { - entity.redirects.push(entity.permalink.replace(/\.x?html?$/, '/index.html')); - } else { - // found index, ignoring redirect - } + // catches /a, /a/index.html, a/index.html + // but not index.html /index.html + if (/^.+\/(index\.x?html?)$/.test(entity.permalink)) { + entity.redirects.push( + entity.permalink.replace(/\/(index.x?html?)?$/, ".html") + ); + } else if (/\.x?html?$/.test(entity.permalink)) { + entity.redirects.push( + entity.permalink.replace(/\.x?html?$/, "/index.html") + ); + } else { + // found index, ignoring redirect + } - // TODO why are redirects broken? - var redirectHtml = Mustache.render(desi.partials.redirect, view) - ; - - entity.redirects.forEach(function (redirect) { - - compiled.push({ - contents: redirectHtml - , path: redirect + // TODO why are redirects broken? + var redirectHtml = Mustache.render(desi.partials.redirect, view); + entity.redirects.forEach(function (redirect) { + compiled.push({ + contents: redirectHtml, + path: redirect, + }); }); + }) + .catch(function (e) { + if (env.onError) { + return env.onError(e); + } else { + console.error("couldn't render " + entity.path); + console.error(entity); + console.error(e); + throw e; + } }); - }).catch(function (e) { - if (env.onError) { - return env.onError(e); - } else { - console.error("couldn't render " + entity.path); - console.error(entity); - console.error(e); - throw e; - } - }); } function doStuff() { - var themes = desi.content.themes.filter(function (f) { return !/\blayouts\b/.test(f.path); }) - ; - - console.info('[first] compiling theme assets'); + var themes = desi.content.themes.filter(function (f) { + return !/\blayouts\b/.test(f.path); + }); + console.info("[first] compiling theme assets"); return forEachAsync(themes, compileThemeEntity).then(function () { - console.info('compiling article pages'); - return forEachAsync(desi.content.collections, compileContentEntity).then(function () { - console.info('compiling root pages'); - return forEachAsync(desi.content.root, compileContentEntity); - }).then(function () { - desi.compiled = compiled; - return desi; - }); + console.info("compiling article pages"); + return forEachAsync(desi.content.collections, compileContentEntity) + .then(function () { + console.info("compiling root pages"); + return forEachAsync(desi.content.root, compileContentEntity); + }) + .then(function () { + desi.compiled = compiled; + return desi; + }); }); } @@ -1053,27 +1101,26 @@ }) .then(function () { return Desi.build(desi, env); - }).then(function () { + }) + .then(function () { return Desi.copyAssets(desi, env); - }).catch(function (e) { + }) + .catch(function (e) { if (env.onError) { return env.onError(e); } else { - console.error('buildAll failed somewhere'); + console.error("buildAll failed somewhere"); console.error(e); throw e; } - }) - ; + }); }; Desi.write = function (desi, env) { - var compiled = desi.compiled.slice(0) - , batches = [] - , now - , size = 0 - ; - + var compiled = desi.compiled.slice(0), + batches = [], + now, + size = 0; if (!compiled.length) { return; } @@ -1095,7 +1142,7 @@ size += saved.size; if (saved.error) { - console.error('[ERROR] saving fsapi batch at root'); + console.error("[ERROR] saving fsapi batch at root"); console.error(saved.error); throw new Error(saved.error); } @@ -1105,20 +1152,20 @@ } saved.errors.forEach(function (e) { - console.error('[ERROR] saving fsapi batch'); + console.error("[ERROR] saving fsapi batch"); console.error(e); throw new Error(e); }); }); }).then(function () { return { - numFiles: desi.compiled.length - , size: size - , start: now - , end: Date.now() + numFiles: desi.compiled.length, + size: size, + start: now, + end: Date.now(), }; }); }; exports.Desirae = Desi.Desirae = Desi; -}('undefined' !== typeof exports && exports || window)); +})(("undefined" !== typeof exports && exports) || window); diff --git a/lib/aggregate-core.js b/lib/aggregate-core.js index 84b93a0..3248b54 100644 --- a/lib/aggregate-core.js +++ b/lib/aggregate-core.js @@ -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); diff --git a/lib/browser-adapters.js b/lib/browser-adapters.js index beff2e3..2af4666 100644 --- a/lib/browser-adapters.js +++ b/lib/browser-adapters.js @@ -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); diff --git a/lib/convert-ruhoh-config.js b/lib/convert-ruhoh-config.js index acc1df2..589fce2 100644 --- a/lib/convert-ruhoh-config.js +++ b/lib/convert-ruhoh-config.js @@ -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."); }; diff --git a/lib/datamap-core.js b/lib/datamap-core.js index ba46db5..ea1c580 100644 --- a/lib/datamap-core.js +++ b/lib/datamap-core.js @@ -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); diff --git a/lib/frontmatter.js b/lib/frontmatter.js index 36fa9f8..5531be0 100644 --- a/lib/frontmatter.js +++ b/lib/frontmatter.js @@ -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); diff --git a/lib/node-adapters/fsapi-real.js b/lib/node-adapters/fsapi-real.js index 3a5c01c..6c7c468 100644 --- a/lib/node-adapters/fsapi-real.js +++ b/lib/node-adapters/fsapi-real.js @@ -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); } }); diff --git a/lib/node-adapters/fsapi.js b/lib/node-adapters/fsapi.js index ddcbd78..3b53c74 100644 --- a/lib/node-adapters/fsapi.js +++ b/lib/node-adapters/fsapi.js @@ -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) { diff --git a/lib/node-adapters/index.js b/lib/node-adapters/index.js index f430db8..1eea423 100644 --- a/lib/node-adapters/index.js +++ b/lib/node-adapters/index.js @@ -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"); diff --git a/lib/node-adapters/sha1sum.js b/lib/node-adapters/sha1sum.js index ff11556..2c379ff 100644 --- a/lib/node-adapters/sha1sum.js +++ b/lib/node-adapters/sha1sum.js @@ -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)); }; diff --git a/lib/render-core.js b/lib/render-core.js index 56658be..f29a9bb 100644 --- a/lib/render-core.js +++ b/lib/render-core.js @@ -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); diff --git a/lib/transform-core.js b/lib/transform-core.js index 2ae91ff..15bee91 100644 --- a/lib/transform-core.js +++ b/lib/transform-core.js @@ -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); diff --git a/lib/utils.js b/lib/utils.js index a1841b9..e531e2e 100644 --- a/lib/utils.js +++ b/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); diff --git a/lib/verify-config.js b/lib/verify-config.js index fd1bf52..9a35989 100644 --- a/lib/verify-config.js +++ b/lib/verify-config.js @@ -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); diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..ebe20b9 --- /dev/null +++ b/package-lock.json @@ -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=" + } + } + } + } +} diff --git a/package.json b/package.json index 7e178fa..5a4bfc8 100644 --- a/package.json +++ b/package.json @@ -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": { diff --git a/tests/permalink.js b/tests/permalink.js index 5ef5ae5..30ffdbe 100644 --- a/tests/permalink.js +++ b/tests/permalink.js @@ -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] ); } });