kinda broken, kinda working
This commit is contained in:
parent
f047b76aa6
commit
b81ed8af1c
|
@ -0,0 +1,56 @@
|
||||||
|
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
|
||||||
|
|
||||||
|
# inherited from Collection Entity
|
||||||
|
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
|
||||||
|
|
||||||
|
# inherited from Normalized Entity
|
||||||
|
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
|
||||||
|
|
||||||
|
categories : ['tech']
|
||||||
|
tags : ['http','url','website']
|
||||||
|
|
||||||
|
# includes index.html
|
||||||
|
relative_file : /posts/foo/index.html
|
||||||
|
|
||||||
|
# excludes index.html
|
||||||
|
relative_link : /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/
|
||||||
|
|
||||||
|
# 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.
|
847
desirae.js
847
desirae.js
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,121 @@
|
||||||
|
/*jshint -W054 */
|
||||||
|
;(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'
|
||||||
|
};
|
||||||
|
|
||||||
|
function byDate(a, b) {
|
||||||
|
a.year = parseInt(a.year, 10) || 0;
|
||||||
|
b.year = parseInt(b.year, 10) || 0;
|
||||||
|
if (a.year > b.year) {
|
||||||
|
return -1;
|
||||||
|
} else if (a.year < b.year) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.month = parseInt(a.month, 10) || 0;
|
||||||
|
b.month = parseInt(b.month, 10) || 0;
|
||||||
|
if (a.month > b.month) {
|
||||||
|
return -1;
|
||||||
|
} else if (a.month < b.month) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.day = parseInt(a.day, 10) || 0;
|
||||||
|
b.day = parseInt(b.day, 10) || 0;
|
||||||
|
if (a.day > b.day) {
|
||||||
|
return -1;
|
||||||
|
} else if (a.day < b.day) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a.hour > b.hour) {
|
||||||
|
return -1;
|
||||||
|
} else if (a.hour < b.hour) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a.minute > b.minute) {
|
||||||
|
return -1;
|
||||||
|
} else if (a.minute < b.minute) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a.title.toLowerCase() <= b.title.toLowerCase()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function collate(entities, env) {
|
||||||
|
var yearsArr = []
|
||||||
|
;
|
||||||
|
|
||||||
|
entities.forEach(function (f) {
|
||||||
|
var set
|
||||||
|
, yindex = 3000 - f.year
|
||||||
|
, mindex = 12 - f.month
|
||||||
|
;
|
||||||
|
|
||||||
|
f.url = path.join(env.base_path, f.permalink);
|
||||||
|
|
||||||
|
if (!yearsArr[yindex]) {
|
||||||
|
yearsArr[yindex] = { year: f.year, months: [] };
|
||||||
|
}
|
||||||
|
set = yearsArr[yindex];
|
||||||
|
|
||||||
|
if (!set.months[mindex]) {
|
||||||
|
set.months[mindex] = { month: months[parseInt(f.month, 10)], pages: [] };
|
||||||
|
}
|
||||||
|
set = set.months[mindex];
|
||||||
|
|
||||||
|
set.pages.push(f);
|
||||||
|
});
|
||||||
|
|
||||||
|
yearsArr = yearsArr.filter(function (y) {
|
||||||
|
if (!y) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
y.months = y.months.filter(function (m) {
|
||||||
|
return m && m.pages.length;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!y.months.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return { years: yearsArr };
|
||||||
|
}
|
||||||
|
|
||||||
|
cores.collate = function (desi, env) {
|
||||||
|
// TODO categories
|
||||||
|
// TODO tags
|
||||||
|
desi.content.collections.sort(byDate);
|
||||||
|
desi.collated = collate(desi.content.collections, env);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.DesiraeAggregateCore = cores.DesiraeAggregateCore = cores;
|
||||||
|
}('undefined' !== typeof exports && exports || window));
|
|
@ -0,0 +1,11 @@
|
||||||
|
/*jshint -W054 */
|
||||||
|
;(function (exports) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
function desiMap(obj) {
|
||||||
|
obj.desi = obj;
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.DesiraeDatamapCore = desiMap.DesiraeDatamapCore = desiMap;
|
||||||
|
}('undefined' !== typeof exports && exports || window));
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*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 })
|
||||||
|
;
|
||||||
|
|
||||||
|
return PromiseA.resolve(
|
||||||
|
markitdown.render(contentstr)
|
||||||
|
//.replace('"', '"')
|
||||||
|
//.replace(''', "'")
|
||||||
|
//.replace('/', '/')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderNoop(contentstr/*, desi*/) {
|
||||||
|
// hmmm... that was easy
|
||||||
|
return PromiseA.resolve(contentstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderJade(contentstr, desi, options) {
|
||||||
|
options = options || {};
|
||||||
|
if (!('pretty' in options)) {
|
||||||
|
options.pretty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var jade = (exports.jade || require('jade'))
|
||||||
|
, fn = jade.compile(contentstr, options)
|
||||||
|
, html = fn(desi)
|
||||||
|
;
|
||||||
|
|
||||||
|
return PromiseA.resolve(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.DesiraeRenderMarkdown = renderMd.DesiraeRenderMarkdown = renderMd;
|
||||||
|
exports.DesiraeRenderHtml = renderNoop.DesiraeRenderHtml = renderNoop;
|
||||||
|
exports.DesiraeRenderCss = renderNoop.DesiraeRenderCss = renderNoop;
|
||||||
|
exports.DesiraeRenderJs = renderNoop.DesiraeRenderJs = renderNoop;
|
||||||
|
exports.DesiraeRenderJade = renderJade.DesiraeRenderJade = renderJade;
|
||||||
|
}('undefined' !== typeof exports && exports || window));
|
|
@ -0,0 +1,178 @@
|
||||||
|
/*jshint -W054 */
|
||||||
|
;(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`.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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_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__';
|
||||||
|
|
||||||
|
// _root is not subject to the same permalink rules as collections,
|
||||||
|
// so we just go ahead and define that here
|
||||||
|
entity.permalink = entity.yml.permalink || entity.path.replace(/\.\w+$/, '');
|
||||||
|
};
|
||||||
|
|
||||||
|
cores.normalize = function (desi, env, collection, entity) {
|
||||||
|
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
|
||||||
|
).toISOString();
|
||||||
|
}
|
||||||
|
if ('object' === typeof entity.date) {
|
||||||
|
entity.date = entity.date.toISOString();
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// 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 = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.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)
|
||||||
|
Desi.permalinkify(desi, collection.fallback_permalink || collection.permalink, entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (!/\.x?html?$/.test(entity.permalink)) {
|
||||||
|
entity.htmllink = path.join(entity.permalink, 'index.html');
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// The root index is the one exception
|
||||||
|
if (/^(index)?\/?index(\.x?html?)?$/.test(entity.permalink)) {
|
||||||
|
entity.permalink = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.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) {
|
||||||
|
// NOTE: file_url is NOT replaced
|
||||||
|
['url', 'canonical_url', 'production_url', 'relative_url'].forEach(function (url) {
|
||||||
|
entity[url] = entity[url].replace(/\/$/, '/index.html');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
cores.disqus = function (desi, env, collection, entity) {
|
||||||
|
var yml = entity.yml
|
||||||
|
;
|
||||||
|
|
||||||
|
if (yml.uuid) {
|
||||||
|
entity.disqus_identifier = yml.uuid;
|
||||||
|
}
|
||||||
|
entity.disqus_url = entity.production_url;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.DesiraeTransformCore = cores.DesiraeTransformCore = cores;
|
||||||
|
}('undefined' !== typeof exports && exports || window));
|
|
@ -37,101 +37,6 @@ function pad(str, n) {
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
permalinkTransforms = {
|
|
||||||
year: function (entity) {
|
|
||||||
return entity.year;
|
|
||||||
}
|
|
||||||
, month: function (entity) {
|
|
||||||
return pad(entity.month, 2);
|
|
||||||
}
|
|
||||||
, day: function (entity) {
|
|
||||||
return 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.yml.categories||[])[0]||'';
|
|
||||||
}
|
|
||||||
, i_month: function (entity) {
|
|
||||||
return parseInt(entity.month, 10) || 0;
|
|
||||||
}
|
|
||||||
, i_day: function (entity) {
|
|
||||||
return parseInt(entity.day, 10) || 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function permalinker(purl, entity) {
|
|
||||||
var parts = purl.split('/')
|
|
||||||
;
|
|
||||||
|
|
||||||
parts.forEach(function (part, i) {
|
|
||||||
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 (permalinkTransforms[m[1]]) {
|
|
||||||
part = part.replace(':' + m[1], permalinkTransforms[m[1]](entity));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* jshint +W084 */
|
|
||||||
|
|
||||||
parts[i] = part || '';
|
|
||||||
});
|
|
||||||
|
|
||||||
parts.unshift('/');
|
|
||||||
purl = path.join.apply(null, parts);
|
|
||||||
if (!/(\/|\.html?)$/.test(purl)) {
|
|
||||||
// we just default to a slash if you were ambiguous
|
|
||||||
purl += '/';
|
|
||||||
}
|
|
||||||
|
|
||||||
return purl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://www.youtube.com/watch?v=1NryFD9_hR0&list=RDOeLUK4a6Ojc&index=2
|
// https://www.youtube.com/watch?v=1NryFD9_hR0&list=RDOeLUK4a6Ojc&index=2
|
||||||
cases = {
|
cases = {
|
||||||
"/:title.html" : "/my-title.html"
|
"/:title.html" : "/my-title.html"
|
||||||
|
|
Loading…
Reference in New Issue