Skip to content

Commit 86f9f96

Browse files
committed
Initial commit
0 parents  commit 86f9f96

19 files changed

+2171
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules/

LICENCE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Original work Copyright (c) 2016 Philippe FERDINAND
4+
Modified work Copyright (c) 2016 Kam Low
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy of
7+
this software and associated documentation files (the "Software"), to deal in
8+
the Software without restriction, including without limitation the rights to
9+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
10+
the Software, and to permit persons to whom the Software is furnished to do so,
11+
subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in all
14+
copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
18+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
19+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Moxygen
2+
3+
Moxygen is a doxygen XML to markdown converter that fills the need for developers who have been craving a beautiful and minimal documentation alternative for their C++ projects.
4+
5+
The code is a heavily modified port of `doxygen2md` with a focus on generating multi page documentation from doxygen [modules](http://www.stack.nl/~dimitri/doxygen/manual/grouping.html#modules).
6+
7+
Moxygen is the API documentation generator used by LibSourcey, the result of which can be seen [here](http://sourcey.com/libsourcey/).
8+
9+
## Usage
10+
11+
1. Run `doxygen` to generate the XML documentation.
12+
2. Run `moxygen` providing the folder location of the XML documentation.
13+
14+
```
15+
Usage: moxygen [options] <doxygen directory>
16+
17+
Options:
18+
19+
-h, --help output usage information
20+
-V, --version output the version number
21+
-v, --verbose verbose mode
22+
-a, --anchors add anchors to internal links
23+
-g, --modules output doxygen modules into separate files
24+
-l, --language <lang> programming language
25+
-t, --templates <dir> custom templates directory
26+
-o, --output <file> output file (must contain %s when using modules)
27+
```

bin/moxygen.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/usr/bin/env node
2+
'use strict';
3+
4+
var log = require('winston');
5+
var program = require('commander');
6+
var assign = require('object-assign');
7+
var pjson = require('../package.json');
8+
var app = require('../index.js');
9+
10+
program.version(pjson.version)
11+
.usage('[options] <doxygen directory>')
12+
.option('-v, --verbose', 'verbose mode', false)
13+
.option('-a, --anchors', 'add anchors to internal links', false)
14+
.option('-g, --modules', 'output doxygen modules into separate files', false)
15+
.option('-l, --language <lang>', 'programming language', String, 'cpp')
16+
.option('-t, --templates <dir>', 'custom templates directory', String, 'templates')
17+
.option('-o, --output <file>', 'output file (must contain %s when using modules)', String, 'api.md')
18+
.parse(process.argv);
19+
20+
if (program.verbose) {
21+
log.level = 'verbose';
22+
}
23+
24+
if (program.args.length) {
25+
app.run(assign({}, app.defaultOptions, {
26+
directory: program.args[0],
27+
anchors: program.anchors,
28+
modules: program.modules,
29+
language: program.language,
30+
templates: program.templates,
31+
output: program.output
32+
}));
33+
}
34+
else {
35+
program.help();
36+
}

index.js

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/**
2+
* Original work Copyright (c) 2016 Philippe FERDINAND
3+
* Modified work Copyright (c) 2016 Kam Low
4+
*
5+
* @license MIT
6+
**/
7+
'use strict';
8+
9+
var path = require('path');
10+
var util = require('util');
11+
12+
var doxyparser = require('./src/parser');
13+
var templates = require('./src/templates');
14+
var helpers = require('./src/helpers');
15+
16+
module.exports = {
17+
18+
/**
19+
* Default options values.
20+
**/
21+
defaultOptions: {
22+
23+
directory: null, /** Location of the doxygen files **/
24+
anchors: true, /** Generate anchors for internal links **/
25+
groups: true, /** Output doxygen groups separately **/
26+
language: 'cpp', /** Programming language **/
27+
templates: 'templates', /** Templates directory **/
28+
output: 'api.md', /** Output file **/
29+
30+
filters: {
31+
members: [
32+
'public-attrib',
33+
'public-func',
34+
'protected-attrib',
35+
'protected-func'
36+
],
37+
compounds: [
38+
'namespace',
39+
'class',
40+
'struct',
41+
'union',
42+
'typedef'
43+
]
44+
}
45+
},
46+
47+
/**
48+
* Parse files and render the output.
49+
**/
50+
run: function (options) {
51+
52+
// Sanitize options
53+
if (options.groups == options.output.indexOf('%s') === -1)
54+
throw "The `output` file parameter must contain an '%s' for group name" +
55+
"substitution when `groups` are enabled."
56+
57+
if (options.templates == this.defaultOptions.templates)
58+
options.templates = path.join(__dirname, 'templates', options.language);
59+
60+
// Load templates
61+
templates.registerHelpers(options);
62+
templates.load(options.templates);
63+
64+
// Parse files
65+
doxyparser.loadIndex(options, function (err, root) {
66+
67+
// Output groups
68+
if (options.groups) {
69+
root.toArray('compounds', 'group').forEach(function (group) {
70+
group.filterChildren(options.filters, group.id);
71+
72+
var compounds = group.toFilteredArray('compounds');
73+
compounds.unshift(group); // insert group at top
74+
var contents = templates.renderArray(compounds);
75+
helpers.writeFile(util.format(options.output, group.name), contents);
76+
});
77+
}
78+
79+
// Output single file
80+
else {
81+
root.filterChildren(options.filters);
82+
83+
var compounds = root.toFilteredArray('compounds');
84+
var contents = templates.renderArray(compounds);
85+
helpers.writeFile(options.output, contents);
86+
}
87+
});
88+
}
89+
}

package.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"name": "moxygen",
3+
"version": "0.5.0",
4+
"description": "Doxygen XML to Markdown documentation converter",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1"
8+
},
9+
"bin": {
10+
"doxygen2md": "./bin/moxygen.js"
11+
},
12+
"repository": {
13+
"type": "git",
14+
"url": "https://github.com/sourcey/moxygen.git"
15+
},
16+
"keywords": [
17+
"doxygen",
18+
"markdown",
19+
"documentation"
20+
],
21+
"author": "Kam Low",
22+
"license": "MIT",
23+
"dependencies": {
24+
"commander": "^2.9.0",
25+
"handlebars": "^4.0.5",
26+
"object-assign": "^4.1.0",
27+
"winston": "^2.2.0",
28+
"xml2js": "^0.4.16"
29+
}
30+
}

src/compound.js

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/**
2+
* Original work Copyright (c) 2016 Philippe FERDINAND
3+
* Modified work Copyright (c) 2016 Kam Low
4+
*
5+
* @license MIT
6+
**/
7+
'use strict';
8+
9+
var log = require('winston');
10+
11+
function Compound(parent, name) {
12+
this.parent = parent;
13+
this.name = name;
14+
this.compounds = {};
15+
this.members = [];
16+
this.basecompoundref = [];
17+
this.filtered = {};
18+
}
19+
20+
Compound.prototype = {
21+
22+
find: function (name, create) {
23+
var compound = this.compounds[name];
24+
25+
if (!compound && create) {
26+
compound = this.compounds[name] = new Compound(this, name);
27+
}
28+
29+
return compound;
30+
},
31+
32+
toArray: function (type, kind) {
33+
type = type || 'compounds';
34+
var arr = Object.keys(this[type]).map(function(key) {
35+
return this[key];
36+
}.bind(this[type]));
37+
38+
if (type == 'compounds') {
39+
var all = new Array();
40+
arr.forEach(function (compound) {
41+
if (!kind || compound.kind == kind) { //compound &&
42+
all.push(compound);
43+
all = all.concat(compound.toArray(type, kind));
44+
}
45+
}.bind(this));
46+
arr = all;
47+
}
48+
49+
return arr;
50+
},
51+
52+
toFilteredArray: function (type) {
53+
type = type || 'compounds';
54+
var all = [];
55+
56+
(this.filtered[type] || []).forEach(function (item) {
57+
var children = item.toFilteredArray(type);
58+
all.push(item);
59+
all = all.concat(children);
60+
});
61+
62+
return all;
63+
},
64+
65+
filterChildren: function (filters, groupid) {
66+
this.toArray('compounds').forEach(function (compound) {
67+
compound.filtered.members = compound.filter(compound.members, 'section', filters.members, groupid);
68+
compound.filtered.compounds = compound.filter(compound.compounds, 'kind', filters.compounds, groupid);
69+
});
70+
this.filtered.compounds = this.filter(this.compounds, 'kind', filters.compounds, groupid);
71+
},
72+
73+
filter: function (collection, key, filter, groupid) {
74+
var categories = {};
75+
var result = [];
76+
77+
Object.keys(collection).forEach(function (name) {
78+
var item = collection[name];
79+
if (item) {
80+
81+
// skip empty namespaces
82+
if (item.kind == 'namespace') {
83+
if ((!item.filtered.compounds || !item.filtered.compounds.length) &&
84+
(!item.filtered.members || !item.filtered.members.length)) {
85+
// log.verbose('Skip empty namespace', item.name);
86+
return;
87+
}
88+
}
89+
90+
// skip items not belonging to current group
91+
else if (groupid && item.groupid != groupid) {
92+
// log.verbose('Skip item from foreign group', item.kind, item.name, item.groupid, group.id);
93+
return;
94+
}
95+
96+
(categories[item[key]] || (categories[item[key]] = [])).push(item);
97+
}
98+
}.bind(this));
99+
100+
filter.forEach(function (category) {
101+
result = result.concat(categories[category] || []);
102+
});
103+
104+
return result;
105+
}
106+
}
107+
108+
module.exports = Compound;

src/helpers.js

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/**
2+
* Original work Copyright (c) 2016 Philippe FERDINAND
3+
* Modified work Copyright (c) 2016 Kam Low
4+
*
5+
* @license MIT
6+
**/
7+
'use strict';
8+
9+
var fs = require('fs');
10+
var path = require('path');
11+
var util = require('util');
12+
var handlebars = require('handlebars');
13+
14+
module.exports = {
15+
16+
inline: function(code) {
17+
if (Array.isArray(code)) {
18+
var refs, s = '', isInline = false;
19+
code.forEach(function (e) {
20+
refs = e.split(/(\[.*\]\(.*\)|\n|\s{2}\n)/g);
21+
refs.forEach(function (f) {
22+
if (f.charAt(0) == '[') {
23+
// link
24+
var link = f.match(/\[(.*)\]\((.*)\)/);
25+
isInline ? (s += '`') && (isInline = false) : null;
26+
s += '[`' + link[1] + '`](' + link[2] + ')';
27+
}
28+
else if (f == '\n' || f == ' \n') {
29+
// line break
30+
isInline ? (s += '`') && (isInline = false) : null;
31+
s += f;
32+
}
33+
else if (f) {
34+
!isInline ? (s += '`') && (isInline = true) : null;
35+
s += f;
36+
}
37+
});
38+
});
39+
return s + (isInline ? '`' : '');
40+
}
41+
else {
42+
return '`' + code + '`';
43+
}
44+
},
45+
46+
// Replace group links to point to correct output file
47+
replaceGroupReflink: function (outfile, references, str) {
48+
var match = str.match(/\((#(.*))\)/),
49+
anchor = match[1],
50+
refid = match[2],
51+
ref = references[refid];
52+
if (ref && ref.groupname) {
53+
var href = util.format(outfile, ref.groupname) + anchor;
54+
str = str.replace(/\((#(.*))\)/, '(' + href + ')')
55+
}
56+
return str;
57+
},
58+
59+
// Write the output file
60+
writeFile: function (filepath, contents) {
61+
var stream = fs.createWriteStream(filepath);
62+
stream.once('open', function(fd) {
63+
contents.forEach(function (content) {
64+
stream.write(content);
65+
});
66+
stream.end();
67+
});
68+
}
69+
};

0 commit comments

Comments
 (0)