Skip to content

Commit

Permalink
0.0.0
Browse files Browse the repository at this point in the history
0.0.0
  • Loading branch information
gabrielcsapo committed Nov 17, 2017
1 parent 38999bf commit 4c867a9
Show file tree
Hide file tree
Showing 22 changed files with 1,108 additions and 2 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
coverage
15 changes: 15 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"extends": "eslint:recommended",
"env": {
"es6": true,
"node": true
},
"rules": {
"quotes": ["error", "single"],
"semi": ["error", "always"]
},
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module"
}
}
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pids
*.pid
*.seed
*.pid.lock
package-lock.json

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
Expand Down Expand Up @@ -56,4 +57,4 @@ typings/

# dotenv environment variables file
.env

.DS_Store
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# 0.0.0 (11/17/2017)

- idea started
25 changes: 24 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,25 @@
# sweeney
💈 a blog-aware, static site generator

> 💈 a blog-aware, static site generator
[![Npm Version](https://img.shields.io/npm/v/sweeney.svg)](https://www.npmjs.com/package/sweeney)
[![Build Status](https://travis-ci.org/gabrielcsapo/sweeney.svg?branch=master)](https://travis-ci.org/gabrielcsapo/sweeney)
[![Coverage Status](https://lcov-server.gabrielcsapo.com/badge/github%2Ecom/gabrielcsapo/sweeney.svg)](https://lcov-server.gabrielcsapo.com/coverage/github%2Ecom/gabrielcsapo/sweeney)
[![Dependency Status](https://starbuck.gabrielcsapo.com/badge/github/gabrielcsapo/sweeney/status.svg)](https://starbuck.gabrielcsapo.com/github/gabrielcsapo/sweeney)
[![devDependency Status](https://starbuck.gabrielcsapo.com/badge/github/gabrielcsapo/sweeney/dev-status.svg)](https://starbuck.gabrielcsapo.com/github/gabrielcsapo/sweeney#info=devDependencies)
[![npm](https://img.shields.io/npm/dt/sweeney.svg)]()
[![npm](https://img.shields.io/npm/dm/sweeney.svg)]()

## Installation

```
npm install sweeney -g
```

## Usage

> work in progress!
## Philosophy 🧠

> a zero dependency tool
4 changes: 4 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- [ ] support markdown footnotes
- [ ] add `serve` command to be able to generate a http server to show realtime changes
- [ ] add `new` command to bootstrap a template application in the given directory
- [ ] add `build` command which should use the sweeney.js file to build the site
12 changes: 12 additions & 0 deletions bin/sweeney.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env node

const args = process.argv.slice(2);

switch(args[0]) {
case 'build':
console.log('not implemented :('); // eslint-disable-line
break;
default:
console.log(`sorry the command ${args[0]} is not supported`); // eslint-disable-line
break;
}
Empty file added lib/build.js
Empty file.
193 changes: 193 additions & 0 deletions lib/markdown.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
// createParser and createBodyParser creates parsers. A parser takes a string,
// and if successful returns an array of two elements. The object representation
// of consumed portion and the remainder of of the string. If failure returns null.

class Markdown {
constructor(src) {
this.src = src;
this.ast = {};
}
// createParser takes a parser type, and regex pattern and
// returns the corresponding parser function. The first match
// in parenthesis is taken as the content. If this parser does not
// suit your requirement write your own parser.

createParser(type, pattern, match) {
return function(src) {
var found = src.match(pattern);
if (found) {
return match ? match(src, pattern, found) : [{
type: type,
content: found[1]
}, src.replace(pattern, '')];
} else {
return null;
}
};
}
// createBodyParser takes as its first argument the "type" of the parser. The rest of the
// arguments are the parsers that make up the bodyParser
createBodyParser() {
var parsers = Array.prototype.slice.call(arguments);
var ast = {
type: parsers.shift(),
body: []
};

return function bodyParser(src) {
for (var i = 0; i < parsers.length; i++) {
var parser = parsers[i];
var test = parser(src);
if (test) {
ast.body.push(test[0]);
return bodyParser(test[1]);
}
}
if (ast.body.length === 0) {
return null;
} else {
var ret = [ast, src];
ast = {
type: ast.type,
body: []
};
return ret;
}
};
}
attributesToHTML(attributes) {
return Object.keys(attributes).filter((a) => {
return ['content'].indexOf(a) === -1;
}).map((a) => {
return `${a}="${attributes[a]}"`;
}).join(' ');
}
toHTML(ast) {
var html = '';

ast.forEach((a) => {
switch(a.type) {
case 'markdown':
html += this.toHTML(a.body);
break;
case 'table':
html += `<table>
${a.header ? `<tr>
${a.header.map((h) => `<th>${h}</th>`).join('')}
<tr>` : ''}
${a.cells ?
a.cells.map((row) => {
return `<tr>
${row.map((c) => `<td>${c}</td>`).join('')}
</tr>`;
}).join('')
: ''}
</table>`;
break;
case 'newline':
html += a.content.replace(/\n/g, '<br/>');
break;
case 'paragraph':
html += `<p>
${this.toHTML(a.body)}
</p>`;
break;
case 'inlinetext':
html += a.content;
break;
case 'link':
html += `<a ${this.attributesToHTML(a)}>${a.content}</a>`;
break;
}
});

return html;
}
parse(src) {
let { createParser, createBodyParser } = this;

return createBodyParser('markdown',
function options(src) {
var pattern = /^(-{3}(?:\n|\r)([\w\W]+?)(?:\n|\r)-{3})?/;
var found = pattern.exec(src);
if (found[2]) {
return [{
type: 'options',
content: JSON.parse(found[2])
}, src.replace(pattern, '')];
} else {
return null;
}
},
createParser('newline', /^(\n+)/),
createParser('h1', /^# ([^\n]+)/),
createParser('h2', /^## ([^\n]+)/),
createParser('h3', /^### ([^\n]+)/),
createParser('h4', /^#### ([^\n]+)/),
createParser('h5', /^##### ([^\n]+)/),
createParser('h6', /^###### ([^\n]+)/),
createParser('table', /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/, (src, pattern, match) => {
const TABLE_HEADER_TRIM = /^ *| *\| *$/g;
const TABLE_ALIGN_TRIM = /^ *|\| *$/g;
const TABLE_CELLS_TRIM = /(?: *\| *)?\n$/;
const PLAIN_TABLE_ROW_TRIM = /^ *\| *| *\| *$/g;
const TABLE_ROW_SPLIT = / *\| */;
const TABLE_RIGHT_ALIGN = /^ *-+: *$/;
const TABLE_CENTER_ALIGN = /^ *:-+: *$/;
const TABLE_LEFT_ALIGN = /^ *:-+ *$/;

function parseTableAlignCapture(alignCapture) {
if (TABLE_RIGHT_ALIGN.test(alignCapture)) return 'right';
if (TABLE_CENTER_ALIGN.test(alignCapture)) return 'center';
if (TABLE_LEFT_ALIGN.test(alignCapture)) return 'left';
return null;
}

function parseTableHeader(capture) {
return capture[1].replace(TABLE_HEADER_TRIM, '').split(TABLE_ROW_SPLIT);
}

function parseTableAlign(capture) {
var alignText = capture[2].replace(TABLE_ALIGN_TRIM, '').split(TABLE_ROW_SPLIT);

return alignText.map(parseTableAlignCapture);
}

function parseTableCells(capture) {
var rowsText = capture[3].replace(TABLE_CELLS_TRIM, '').split('\n');

return rowsText.map((rowText) => {
return rowText.replace(PLAIN_TABLE_ROW_TRIM, '').split(TABLE_ROW_SPLIT);
});
}

const header = parseTableHeader(match);
const align = parseTableAlign(match);
const cells = parseTableCells(match);

return [{ type: 'table', header, align, cells }, src.replace(pattern, '')];
}),
createParser('blockquote', /^> ([^\n]+)/),
createBodyParser('codeblock',
createParser('code', /^ {4}([^\n]+)\n/)
),
createBodyParser('listblock',
createParser('list', /^\* ([^\n]+)\n/),
createParser('list', /^- ([^\n]+)\n/)
),
createBodyParser('orderedListblock',
createParser('orderedList', /^[0-9]+ ([^\n]+)\n/)
),
createBodyParser('paragraph',
createParser('inlinetext', /^([^\n[!*]+)/),
createParser('link', /^\[(.+?)\]\((.+?)\)/, (src, pattern, match) => [{ type: 'link', content: match[1], href: match[2] }, src.replace(pattern, '')]),
createParser('image', /^!\[(.+?)\]\((.+?)\)/, (src, pattern, match) => [{ type: 'image', alt: match[1], href: match[2] }, src.replace(pattern, '')]),
createParser('emphasis', /^\*(.+?)\*/),
createParser('strong', /^\*\*(.+?)\*\*/),
createParser('text', /^([^\n]+)/)
)
)(src);
}
}

module.exports = new Markdown();
22 changes: 22 additions & 0 deletions lib/template.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const fs = require('fs');
const path = require('path');

module.exports = function template(str, data, directory) {
function include(file) {
return template(fs.readFileSync(path.resolve(directory, file)).toString(), data, directory);
}
data.include = include;

var fn = new Function('obj', 'var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push(\'' +
str
.replace(/[\r\t\n]/g, ' ')
.split('{{').join('\t')
.replace(/((^|\}\})[^\t]*)'/g, '$1\r')
.replace(/\t(.*?)\}\}/g, '\',$1,\'')
.split('\t').join('\');')
.split('}}').join('p.push(\'')
.split('\r').join('\\\'')
+ '\');}return p.join(\'\');');

return data ? fn(data) : fn;
};
29 changes: 29 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "sweeney",
"version": "0.0.0",
"description": "💈 a blog-aware, static site generator",
"author": "Gabriel J. Csapo <gabecsapo@gmail.com>",
"license": "Apache-2.0",
"main": "index.js",
"repository": {
"type": "git",
"url": "git+https://github.com/gabrielcsapo/sweeney.git"
},
"bugs": {
"url": "https://github.com/gabrielcsapo/sweeney/issues"
},
"homepage": "https://github.com/gabrielcsapo/sweeney#readme",
"scripts": {
"lint": "eslint .",
"test": "tape test/**.js",
"coverage": "tap test --coverage --coverage-report=lcov"
},
"bin": {
"sweeney": "./bin/sweeney.js"
},
"devDependencies": {
"eslint": "^4.11.0",
"tap": "^10.7.3",
"tape": "^4.8.0"
}
}
55 changes: 55 additions & 0 deletions test/fixtures/includes/footer.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<footer class="site-footer">

<div class="wrapper">

<h2 class="footer-heading">{{ site.title }}</h2>

<div class="footer-col-wrapper">
<div class="footer-col footer-col-1">
<ul class="contact-list">
<li>{{ site.title }}</li>
<li><a href="mailto:{{ site.user.email }}">{{ site.email }}</a></li>
</ul>
</div>

<div class="footer-col footer-col-2">
<ul class="social-media-list">
{{ site.user.github_username ?
`<li>
<a href="https://github.com/${site.user.github_username}">
<span class="icon icon--github">
<svg viewBox="0 0 16 16">
<path fill="#828282" d="M7.999,0.431c-4.285,0-7.76,3.474-7.76,7.761 c0,3.428,2.223,6.337,5.307,7.363c0.388,0.071,0.53-0.168,0.53-0.374c0-0.184-0.007-0.672-0.01-1.32 c-2.159,0.469-2.614-1.04-2.614-1.04c-0.353-0.896-0.862-1.135-0.862-1.135c-0.705-0.481,0.053-0.472,0.053-0.472 c0.779,0.055,1.189,0.8,1.189,0.8c0.692,1.186,1.816,0.843,2.258,0.645c0.071-0.502,0.271-0.843,0.493-1.037 C4.86,11.425,3.049,10.76,3.049,7.786c0-0.847,0.302-1.54,0.799-2.082C3.768,5.507,3.501,4.718,3.924,3.65 c0,0,0.652-0.209,2.134,0.796C6.677,4.273,7.34,4.187,8,4.184c0.659,0.003,1.323,0.089,1.943,0.261 c1.482-1.004,2.132-0.796,2.132-0.796c0.423,1.068,0.157,1.857,0.077,2.054c0.497,0.542,0.798,1.235,0.798,2.082 c0,2.981-1.814,3.637-3.543,3.829c0.279,0.24,0.527,0.713,0.527,1.437c0,1.037-0.01,1.874-0.01,2.129 c0,0.208,0.14,0.449,0.534,0.373c3.081-1.028,5.302-3.935,5.302-7.362C15.76,3.906,12.285,0.431,7.999,0.431z"/>
</svg>
</span>

<span class="username">${site.user.github_username}</span>
</a>
</li>`
: '' }}

{{ site.user.github_username ?
`<li>
<a href="https://twitter.com/${site.user.twitter_username}">
<span class="icon icon--twitter">
<svg viewBox="0 0 16 16">
<path fill="#828282" d="M15.969,3.058c-0.586,0.26-1.217,0.436-1.878,0.515c0.675-0.405,1.194-1.045,1.438-1.809
c-0.632,0.375-1.332,0.647-2.076,0.793c-0.596-0.636-1.446-1.033-2.387-1.033c-1.806,0-3.27,1.464-3.27,3.27 c0,0.256,0.029,0.506,0.085,0.745C5.163,5.404,2.753,4.102,1.14,2.124C0.859,2.607,0.698,3.168,0.698,3.767 c0,1.134,0.577,2.135,1.455,2.722C1.616,6.472,1.112,6.325,0.671,6.08c0,0.014,0,0.027,0,0.041c0,1.584,1.127,2.906,2.623,3.206 C3.02,9.402,2.731,9.442,2.433,9.442c-0.211,0-0.416-0.021-0.615-0.059c0.416,1.299,1.624,2.245,3.055,2.271 c-1.119,0.877-2.529,1.4-4.061,1.4c-0.264,0-0.524-0.015-0.78-0.046c1.447,0.928,3.166,1.469,5.013,1.469 c6.015,0,9.304-4.983,9.304-9.304c0-0.142-0.003-0.283-0.009-0.423C14.976,4.29,15.531,3.714,15.969,3.058z"/>
</svg>
</span>

<span class="username">${site.user.twitter_username}</span>
</a>
</li>`
: '' }}
</ul>
</div>

<div class="footer-col footer-col-3">
<p class="text">{{ site.description }}</p>
</div>
</div>

</div>

</footer>
9 changes: 9 additions & 0 deletions test/fixtures/includes/head.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width initial-scale=1" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">

<title>{{ page.title || site.title }}</title>
<link rel="stylesheet" href="./site.css">
<meta name="description" content="{{ site.description }}">
</head>
Loading

0 comments on commit 4c867a9

Please sign in to comment.