Skip to content

Commit

Permalink
Navigation item functionality added, some organization changes
Browse files Browse the repository at this point in the history
  • Loading branch information
Sethen committed Mar 3, 2015
1 parent 89ef4a1 commit baf8e78
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 45 deletions.
32 changes: 26 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
* [markdown-include](#markdown-include)
* [Compile your markdown files](#compile-your-markdown-files)
* [Make a table of contents](#make-a-table-of-contents)
* [How To Install](#how-to-install)
* [How To Use](#how-to-use)
* [markdown.json](#markdown.json)
* [How It Works](#how-it-works)


# markdown-include

markdown-include is built using Node.js and allows you to include markdown files into other markdown files using a C style include syntax:
markdown-include is built using Node.js and allows you to include markdown files into other markdown files using a C style include syntax.

## Compile your markdown files

markdown-include's main feature is that it allows you to include allows you to include markdown files into other markdown files, like so:

```
#include "markdown-file.md"
Expand All @@ -26,6 +39,12 @@ Something in markdown file!
Something in another markdown file!
```

## Make a table of contents

Aside from compiling your markdown files, markdown-include can also build your table of contents. This works by evaluating the heading tags inside of your files. Since markdown works on using `#` for headings, this makes it easy to assemble table of contents from them. The more `#` you have in front of your headings (up to 6) will decide how the table of contents is built. Use one `#` and it's a top level navigation item... Use two `#` and it would be underneath the previous navigation item.

For each heading that you would like to be included in a table of contents just add ` !heading` to the end of it.


# How To Install

Expand All @@ -50,15 +69,16 @@ node path/to/markdown-include.js path/to/markdown.json

`markdown.json` can be populated with the following options:

| Option | Type | Description |
|:-------------:|:-------------:|:--------------------------------------------------------------------------:|
| `build` | String | File path of where everything should be compiled, like `README.md` |
| `files` | Array | Array of files to to compile |
| Option | Type | Description |
|:-----------------:|:-------------:|:--------------------------------------------------------------------------:|
| `build` | String | File path of where everything should be compiled, like `README.md` |
| `files` | Array | Array of files to to compile |
| `tableOfContents` | Boolean | `true` to build table of contents dynamically |


# How It Works

markdown-include works by recursively going through files based on the tags that are found. For instance, considering the following in a `_README.md` file:
markdown-include works by recursively going through files based on the tags that are found. For instance, consider the following in a `_README.md` file:

```
#include "first-file.md"
Expand Down
4 changes: 2 additions & 2 deletions docs/how_it_works.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# How It Works
# How It Works !heading

markdown-include works by recursively going through files based on the tags that are found. For instance, considering the following in a `_README.md` file:
markdown-include works by recursively going through files based on the tags that are found. For instance, consider the following in a `_README.md` file:

```
#include "first-file.md" !ignore
Expand Down
2 changes: 1 addition & 1 deletion docs/how_to_install.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# How To Install
# How To Install !heading

markdown-include is available on npm for easy installation:

Expand Down
13 changes: 7 additions & 6 deletions docs/how_to_use.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
# How To Use
# How To Use !heading

markdown-include is very easy to use. Just include a `markdown.json` file in your project root with your options and run from the command line to compile your documents like so:

```
node path/to/markdown-include.js path/to/markdown.json
```

## markdown.json
## markdown.json !heading

`markdown.json` can be populated with the following options:

| Option | Type | Description |
|:-------------:|:-------------:|:--------------------------------------------------------------------------:|
| `build` | String | File path of where everything should be compiled, like `README.md` |
| `files` | Array | Array of files to to compile |
| Option | Type | Description |
|:-----------------:|:-------------:|:--------------------------------------------------------------------------:|
| `build` | String | File path of where everything should be compiled, like `README.md` |
| `files` | Array | Array of files to to compile |
| `tableOfContents` | Boolean | `true` to build table of contents dynamically |

14 changes: 12 additions & 2 deletions docs/markdown_include.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# markdown-include
# markdown-include !heading

markdown-include is built using Node.js and allows you to include markdown files into other markdown files using a C style include syntax:
markdown-include is built using Node.js and allows you to include markdown files into other markdown files using a C style include syntax.

## Compile your markdown files !heading

markdown-include's main feature is that it allows you to include allows you to include markdown files into other markdown files, like so:

```
#include "markdown-file.md" !ignore
Expand All @@ -26,3 +30,9 @@ Something in markdown file!
Something in another markdown file!
```

## Make a table of contents !heading

Aside from compiling your markdown files, markdown-include can also build your table of contents. This works by evaluating the heading tags inside of your files. Since markdown works on using `#` for headings, this makes it easy to assemble table of contents from them. The more `#` you have in front of your headings (up to 6) will decide how the table of contents is built. Use one `#` and it's a top level navigation item... Use two `#` and it would be underneath the previous navigation item.

For each heading that you would like to be included in a table of contents just add ` !heading` to the end of it.

172 changes: 146 additions & 26 deletions markdown-include.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,61 @@
var fs = require('fs');
var includePattern = /^#include\s"(.+\/|\/|\w|-|\/)+.md"/gm;
var ignorePattern = /^#include\s"(.+\/|\/|\w|-|\/)+.md" !ignore/gm;
var headingPattern = /#+\s.+ !heading/gm;
var build = {};
var tableOfContents = '';

/**
* Build files from markdown.json
* Build content item for navigation
* @param {Object} obj Object containing count and headingTag
* @return {String} String for markdown navigation item
*/
function buildContentItem(obj) {
var headingTag = obj.headingTag;
var count = obj.count;
var item = headingTag.substring(count + 1);
var index = headingTag.indexOf(item);
var headingTrimmed = headingTag.substring(index).trim().split(' ').join('-').toLowerCase();
var navItem;

/**
* Small utility function for building links for navigation items
* @param {String} heading Navigation item
* @return {String} Navigation item that's linked
*/
function buildNavItem(heading) {
return '[' + item + '](#' + heading + ')\n';
}

switch (obj.count) {
case 1:
navItem = '* ' + buildNavItem(headingTrimmed);
break;
case 2:
navItem = ' * ' + buildNavItem(headingTrimmed);
break;
case 3:
navItem = ' * ' + buildNavItem(headingTrimmed);
break;
case 4:
navItem = ' * ' + buildNavItem(headingTrimmed);
break;
case 5:
navItem = ' * ' + buildNavItem(headingTrimmed);
break;
case 6:
navItem = ' * ' + buildNavItem(headingTrimmed);
break;
}

return navItem;
}

/**
* Compile files from markdown.json
* @param {String} path File path to markdown.json
*/
function buildFiles(path) {
function compileFiles(path) {
fs.readFile(path, function (err, data) {
if (err) {
throw err;
Expand All @@ -28,13 +76,57 @@

for (i = 0; i < files.length; i += 1) {
var file = files[i];

processFile(file);
replaceIgnoreTags(file);
writeFile(options.build, build[file].parsedData);
build[file].parsedData = stripFileTags({
data: build[file].parsedData,
pattern: ignorePattern,
string: ' !ignore'
});

if (options.tableOfContents) {
compileHeadingTags(file);
build[file].parsedData = tableOfContents + '\n\n' + build[file].parsedData;
}

writeFile(options, build[file].parsedData);
}
});
}


/**
* Compiling heading tags in a parsed file
* @param {String} file File path
*/
function compileHeadingTags(file) {
var headingTags = findHeadingTags(build[file].parsedData);
var replacedHeadingTag;
var parsedHeading;
var i;

for (i = 0; i < headingTags.length; i += 1) {
replacedHeadingTag = headingTags[i].replace(' !heading', '');
parsedHeading = parseHeadingTag(replacedHeadingTag);
tableOfContents += buildContentItem(parsedHeading);
}

build[file].parsedData = stripFileTags({
data: build[file].parsedData,
pattern: headingPattern,
string: ' !heading'
});
}

/**
* Finding heading tags that have !heading
* @param {String} parsedData Parsed data from includes
* @return {Array} Array of matching heading tags
*/
function findHeadingTags(parsedData) {
return parsedData.match(headingPattern) || [];
}

/**
* Finds include tags in file content based on a regular expression
* @param {String} rawData Raw data from file
Expand Down Expand Up @@ -107,6 +199,30 @@
return tag.substring(firstQuote, lastQuote);
}

/**
* [parseHeadingTag description]
* @param {[type]} headingTag [description]
* @return {[type]} [description]
*/
function parseHeadingTag(headingTag) {
var count = 0;
var i;

for (i = 0; i < headingTag.length; i += 1) {
if (headingTag[i] === '#') {
count += 1;
}
else {
break;
}
}

return {
count: count,
headingTag: headingTag
};
}

/**
* Processes array of include tags and passes file for recursion
* @param {String} file File passed for additional processing to check for more includes
Expand Down Expand Up @@ -161,34 +277,38 @@
}

/**
* Replaces include tags with an !ignore
* @param {String} file File path
* Strips tags in a given file
* @param {Object} obj Object containing file path, pattern to match and string to replace
* @return {String} Replaced data from object keys
*/
function replaceIgnoreTags(file) {
var obj = build[file];
var parsedData = obj.parsedData;
function stripFileTags(obj) {
var replacedData;

if (ignorePattern.test(parsedData)) {
var ignores = parsedData.match(ignorePattern);
if (obj.pattern.test(obj.data)) {
var patterns = obj.data.match(obj.pattern);
var i;

for (i = 0; i < ignores.length; i += 1) {
var ignore = ignores[i];
var index = parsedData.indexOf(ignore);
var ignoreLength = ' !ignore'.length;
var ignoreTagLength = ignores[i].length;
var replacedTag = ignore.substring(0, ignoreTagLength - ignoreLength);

if (replacedData) {
replacedData = replacedData.replace(ignore, replacedTag);
for (i = 0; i < patterns.length; i += 1) {
var currentPattern = patterns[i];
var index = obj.data.indexOf(currentPattern);
var stringLength = obj.string.length;
var currentPatternTagLength = patterns[i].length;
var replacedTag = currentPattern.substring(0, currentPatternTagLength - stringLength);

if (obj.replace) {
console.log('do something else');
}
else {
replacedData = obj.parsedData.replace(ignore, replacedTag);
if (replacedData) {
replacedData = replacedData.replace(currentPattern, replacedTag);
}
else {
replacedData = obj.data.replace(currentPattern, replacedTag);
}
}
}

obj.parsedData = replacedData;
return replacedData;
}
}

Expand All @@ -197,15 +317,15 @@
* @param {String} path Path to build new file
* @param {String} data Data to write into file
*/
function writeFile(path, data) {
fs.writeFile(path, data, function (err) {
function writeFile(options, parsedData) {
fs.writeFile(options.build, parsedData, function (err) {
if (err) {
throw err;
}

console.info(path + ' has been built successfully');
console.info(options.build + ' has been built successfully');
});
}

buildFiles(process.argv[2]);
compileFiles(process.argv[2]);
}());
3 changes: 2 additions & 1 deletion markdown.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"build" : "README.md",
"files" : ["./docs/_README.md"]
"files" : ["./docs/_README.md"],
"tableOfContents": true
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "markdown-include",
"version": "0.1.0",
"version": "0.2.0",
"description": "Include markdown files into other markdown files with C style syntax.",
"main": "markdown-include.js",
"repository": {
Expand Down

0 comments on commit baf8e78

Please sign in to comment.