Skip to content

Commit baf8e78

Browse files
author
Sethen
committed
Navigation item functionality added, some organization changes
1 parent 89ef4a1 commit baf8e78

8 files changed

+197
-45
lines changed

README.md

+26-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,19 @@
1+
* [markdown-include](#markdown-include)
2+
* [Compile your markdown files](#compile-your-markdown-files)
3+
* [Make a table of contents](#make-a-table-of-contents)
4+
* [How To Install](#how-to-install)
5+
* [How To Use](#how-to-use)
6+
* [markdown.json](#markdown.json)
7+
* [How It Works](#how-it-works)
8+
9+
110
# markdown-include
211

3-
markdown-include is built using Node.js and allows you to include markdown files into other markdown files using a C style include syntax:
12+
markdown-include is built using Node.js and allows you to include markdown files into other markdown files using a C style include syntax.
13+
14+
## Compile your markdown files
15+
16+
markdown-include's main feature is that it allows you to include allows you to include markdown files into other markdown files, like so:
417

518
```
619
#include "markdown-file.md"
@@ -26,6 +39,12 @@ Something in markdown file!
2639
Something in another markdown file!
2740
```
2841

42+
## Make a table of contents
43+
44+
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.
45+
46+
For each heading that you would like to be included in a table of contents just add ` !heading` to the end of it.
47+
2948

3049
# How To Install
3150

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

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

53-
| Option | Type | Description |
54-
|:-------------:|:-------------:|:--------------------------------------------------------------------------:|
55-
| `build` | String | File path of where everything should be compiled, like `README.md` |
56-
| `files` | Array | Array of files to to compile |
72+
| Option | Type | Description |
73+
|:-----------------:|:-------------:|:--------------------------------------------------------------------------:|
74+
| `build` | String | File path of where everything should be compiled, like `README.md` |
75+
| `files` | Array | Array of files to to compile |
76+
| `tableOfContents` | Boolean | `true` to build table of contents dynamically |
5777

5878

5979
# How It Works
6080

61-
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:
81+
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:
6282

6383
```
6484
#include "first-file.md"

docs/how_it_works.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# How It Works
1+
# How It Works !heading
22

3-
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:
3+
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:
44

55
```
66
#include "first-file.md" !ignore

docs/how_to_install.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# How To Install
1+
# How To Install !heading
22

33
markdown-include is available on npm for easy installation:
44

docs/how_to_use.md

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
1-
# How To Use
1+
# How To Use !heading
22

33
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:
44

55
```
66
node path/to/markdown-include.js path/to/markdown.json
77
```
88

9-
## markdown.json
9+
## markdown.json !heading
1010

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

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

docs/markdown_include.md

+12-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1-
# markdown-include
1+
# markdown-include !heading
22

3-
markdown-include is built using Node.js and allows you to include markdown files into other markdown files using a C style include syntax:
3+
markdown-include is built using Node.js and allows you to include markdown files into other markdown files using a C style include syntax.
4+
5+
## Compile your markdown files !heading
6+
7+
markdown-include's main feature is that it allows you to include allows you to include markdown files into other markdown files, like so:
48

59
```
610
#include "markdown-file.md" !ignore
@@ -26,3 +30,9 @@ Something in markdown file!
2630
Something in another markdown file!
2731
```
2832

33+
## Make a table of contents !heading
34+
35+
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.
36+
37+
For each heading that you would like to be included in a table of contents just add ` !heading` to the end of it.
38+

markdown-include.js

+146-26
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,61 @@
1010
var fs = require('fs');
1111
var includePattern = /^#include\s"(.+\/|\/|\w|-|\/)+.md"/gm;
1212
var ignorePattern = /^#include\s"(.+\/|\/|\w|-|\/)+.md" !ignore/gm;
13+
var headingPattern = /#+\s.+ !heading/gm;
1314
var build = {};
15+
var tableOfContents = '';
1416

1517
/**
16-
* Build files from markdown.json
18+
* Build content item for navigation
19+
* @param {Object} obj Object containing count and headingTag
20+
* @return {String} String for markdown navigation item
21+
*/
22+
function buildContentItem(obj) {
23+
var headingTag = obj.headingTag;
24+
var count = obj.count;
25+
var item = headingTag.substring(count + 1);
26+
var index = headingTag.indexOf(item);
27+
var headingTrimmed = headingTag.substring(index).trim().split(' ').join('-').toLowerCase();
28+
var navItem;
29+
30+
/**
31+
* Small utility function for building links for navigation items
32+
* @param {String} heading Navigation item
33+
* @return {String} Navigation item that's linked
34+
*/
35+
function buildNavItem(heading) {
36+
return '[' + item + '](#' + heading + ')\n';
37+
}
38+
39+
switch (obj.count) {
40+
case 1:
41+
navItem = '* ' + buildNavItem(headingTrimmed);
42+
break;
43+
case 2:
44+
navItem = ' * ' + buildNavItem(headingTrimmed);
45+
break;
46+
case 3:
47+
navItem = ' * ' + buildNavItem(headingTrimmed);
48+
break;
49+
case 4:
50+
navItem = ' * ' + buildNavItem(headingTrimmed);
51+
break;
52+
case 5:
53+
navItem = ' * ' + buildNavItem(headingTrimmed);
54+
break;
55+
case 6:
56+
navItem = ' * ' + buildNavItem(headingTrimmed);
57+
break;
58+
}
59+
60+
return navItem;
61+
}
62+
63+
/**
64+
* Compile files from markdown.json
1765
* @param {String} path File path to markdown.json
1866
*/
19-
function buildFiles(path) {
67+
function compileFiles(path) {
2068
fs.readFile(path, function (err, data) {
2169
if (err) {
2270
throw err;
@@ -28,13 +76,57 @@
2876

2977
for (i = 0; i < files.length; i += 1) {
3078
var file = files[i];
79+
3180
processFile(file);
32-
replaceIgnoreTags(file);
33-
writeFile(options.build, build[file].parsedData);
81+
build[file].parsedData = stripFileTags({
82+
data: build[file].parsedData,
83+
pattern: ignorePattern,
84+
string: ' !ignore'
85+
});
86+
87+
if (options.tableOfContents) {
88+
compileHeadingTags(file);
89+
build[file].parsedData = tableOfContents + '\n\n' + build[file].parsedData;
90+
}
91+
92+
writeFile(options, build[file].parsedData);
3493
}
3594
});
3695
}
3796

97+
98+
/**
99+
* Compiling heading tags in a parsed file
100+
* @param {String} file File path
101+
*/
102+
function compileHeadingTags(file) {
103+
var headingTags = findHeadingTags(build[file].parsedData);
104+
var replacedHeadingTag;
105+
var parsedHeading;
106+
var i;
107+
108+
for (i = 0; i < headingTags.length; i += 1) {
109+
replacedHeadingTag = headingTags[i].replace(' !heading', '');
110+
parsedHeading = parseHeadingTag(replacedHeadingTag);
111+
tableOfContents += buildContentItem(parsedHeading);
112+
}
113+
114+
build[file].parsedData = stripFileTags({
115+
data: build[file].parsedData,
116+
pattern: headingPattern,
117+
string: ' !heading'
118+
});
119+
}
120+
121+
/**
122+
* Finding heading tags that have !heading
123+
* @param {String} parsedData Parsed data from includes
124+
* @return {Array} Array of matching heading tags
125+
*/
126+
function findHeadingTags(parsedData) {
127+
return parsedData.match(headingPattern) || [];
128+
}
129+
38130
/**
39131
* Finds include tags in file content based on a regular expression
40132
* @param {String} rawData Raw data from file
@@ -107,6 +199,30 @@
107199
return tag.substring(firstQuote, lastQuote);
108200
}
109201

202+
/**
203+
* [parseHeadingTag description]
204+
* @param {[type]} headingTag [description]
205+
* @return {[type]} [description]
206+
*/
207+
function parseHeadingTag(headingTag) {
208+
var count = 0;
209+
var i;
210+
211+
for (i = 0; i < headingTag.length; i += 1) {
212+
if (headingTag[i] === '#') {
213+
count += 1;
214+
}
215+
else {
216+
break;
217+
}
218+
}
219+
220+
return {
221+
count: count,
222+
headingTag: headingTag
223+
};
224+
}
225+
110226
/**
111227
* Processes array of include tags and passes file for recursion
112228
* @param {String} file File passed for additional processing to check for more includes
@@ -161,34 +277,38 @@
161277
}
162278

163279
/**
164-
* Replaces include tags with an !ignore
165-
* @param {String} file File path
280+
* Strips tags in a given file
281+
* @param {Object} obj Object containing file path, pattern to match and string to replace
282+
* @return {String} Replaced data from object keys
166283
*/
167-
function replaceIgnoreTags(file) {
168-
var obj = build[file];
169-
var parsedData = obj.parsedData;
284+
function stripFileTags(obj) {
170285
var replacedData;
171286

172-
if (ignorePattern.test(parsedData)) {
173-
var ignores = parsedData.match(ignorePattern);
287+
if (obj.pattern.test(obj.data)) {
288+
var patterns = obj.data.match(obj.pattern);
174289
var i;
175290

176-
for (i = 0; i < ignores.length; i += 1) {
177-
var ignore = ignores[i];
178-
var index = parsedData.indexOf(ignore);
179-
var ignoreLength = ' !ignore'.length;
180-
var ignoreTagLength = ignores[i].length;
181-
var replacedTag = ignore.substring(0, ignoreTagLength - ignoreLength);
182-
183-
if (replacedData) {
184-
replacedData = replacedData.replace(ignore, replacedTag);
291+
for (i = 0; i < patterns.length; i += 1) {
292+
var currentPattern = patterns[i];
293+
var index = obj.data.indexOf(currentPattern);
294+
var stringLength = obj.string.length;
295+
var currentPatternTagLength = patterns[i].length;
296+
var replacedTag = currentPattern.substring(0, currentPatternTagLength - stringLength);
297+
298+
if (obj.replace) {
299+
console.log('do something else');
185300
}
186301
else {
187-
replacedData = obj.parsedData.replace(ignore, replacedTag);
302+
if (replacedData) {
303+
replacedData = replacedData.replace(currentPattern, replacedTag);
304+
}
305+
else {
306+
replacedData = obj.data.replace(currentPattern, replacedTag);
307+
}
188308
}
189309
}
190310

191-
obj.parsedData = replacedData;
311+
return replacedData;
192312
}
193313
}
194314

@@ -197,15 +317,15 @@
197317
* @param {String} path Path to build new file
198318
* @param {String} data Data to write into file
199319
*/
200-
function writeFile(path, data) {
201-
fs.writeFile(path, data, function (err) {
320+
function writeFile(options, parsedData) {
321+
fs.writeFile(options.build, parsedData, function (err) {
202322
if (err) {
203323
throw err;
204324
}
205325

206-
console.info(path + ' has been built successfully');
326+
console.info(options.build + ' has been built successfully');
207327
});
208328
}
209329

210-
buildFiles(process.argv[2]);
330+
compileFiles(process.argv[2]);
211331
}());

markdown.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
22
"build" : "README.md",
3-
"files" : ["./docs/_README.md"]
3+
"files" : ["./docs/_README.md"],
4+
"tableOfContents": true
45
}

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "markdown-include",
3-
"version": "0.1.0",
3+
"version": "0.2.0",
44
"description": "Include markdown files into other markdown files with C style syntax.",
55
"main": "markdown-include.js",
66
"repository": {

0 commit comments

Comments
 (0)