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;
|
||||
}
|
||||
|
||||
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
|
||||
cases = {
|
||||
"/:title.html" : "/my-title.html"
|
||||
|
|
Loading…
Reference in New Issue