├── example ├── doc │ ├── .gitkeep │ ├── page-changelog.md │ ├── page-overview.md │ ├── api-racingbike.md │ ├── api-bicycle.md │ └── api-mountainbike.md ├── src │ ├── mountainbike.cpp │ ├── racingbike.cpp │ ├── changelog.md │ ├── bicycle.cpp │ ├── overview.md │ ├── racingbike.h │ ├── bicycle.h │ ├── transport.h │ └── mountainbike.h └── xml │ ├── combine.xslt │ ├── group__bicycle.xml │ ├── group__mountainbike.xml │ ├── group__racingbike.xml │ ├── namespacetransport.xml │ ├── changelog.xml │ ├── dir_68267d1309a1af8e8297ef4c3efbcdba.xml │ ├── overview.xml │ ├── changelog_8md.xml │ ├── overview_8md.xml │ ├── mountainbike_8cpp.xml │ ├── index.xsd │ ├── racingbike_8cpp.xml │ ├── bicycle_8cpp.xml │ ├── index.xml │ ├── bicycle_8h.xml │ ├── classtransport_1_1RacingBike.xml │ ├── racingbike_8h.xml │ ├── classtransport_1_1Bicycle.xml │ ├── classtransport_1_1MountainBike.xml │ ├── mountainbike_8h.xml │ ├── transport_8h.xml │ └── compound.xsd ├── .gitignore ├── TODO.md ├── src ├── markdown.js ├── logger.js ├── templates.js ├── compound.js ├── helpers.js └── parser.js ├── templates └── cpp │ ├── index.md │ ├── namespace.md │ ├── page.md │ └── class.md ├── package.json ├── LICENCE ├── bin └── moxygen.js ├── README.md └── index.js /example/doc/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | package-lock.json 4 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | test free function 2 | 3 | add links to all member entities in index 4 | Add tidy-markdown when stable (2.0.5 is broken) 5 | 6 | 7 | DONE 8 | -------------------------------------------------------------------------------- /example/src/mountainbike.cpp: -------------------------------------------------------------------------------- 1 | #include "mountainbike.h" 2 | 3 | using namespace transport; 4 | 5 | bool 6 | MountainBike::SetSuspension(double stiffness) 7 | { 8 | return true; 9 | } 10 | -------------------------------------------------------------------------------- /example/src/racingbike.cpp: -------------------------------------------------------------------------------- 1 | #include "racingbike.h" 2 | 3 | using namespace transport; 4 | 5 | void 6 | RacingBike::RingBell() 7 | { 8 | } 9 | 10 | void 11 | RacingBike::PedalHarder() 12 | { 13 | } 14 | -------------------------------------------------------------------------------- /example/src/changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog {#changelog} 2 | 3 | ## Version 1.0.1 4 | 5 | - Pedalling harder no longer stands in the saddle by default. This is just better form. 6 | 7 | ## Version 1.0.0 8 | 9 | - Initial release -------------------------------------------------------------------------------- /example/src/bicycle.cpp: -------------------------------------------------------------------------------- 1 | #include "bicycle.h" 2 | 3 | using namespace transport; 4 | 5 | Bicycle::~Bicycle() 6 | { 7 | } 8 | 9 | void 10 | Bicycle::RingBell() 11 | { 12 | } 13 | 14 | void 15 | Bicycle::PedalHarder() 16 | { 17 | } 18 | -------------------------------------------------------------------------------- /example/doc/page-changelog.md: -------------------------------------------------------------------------------- 1 | # page `changelog` {#changelog} 2 | 3 | ## Version 1.0.1 4 | 5 | * Pedalling harder no longer stands in the saddle by default. This is just better form. 6 | 7 | ## Version 1.0.0 8 | 9 | * Initial release 10 | 11 | -------------------------------------------------------------------------------- /example/src/overview.md: -------------------------------------------------------------------------------- 1 | # Transport {#overview} 2 | 3 | The `transport` namespace provides several differnt types of bycicles, including transport::Bicycle, transport::MountainBike (designed for rough terrain), and transport::RacingBike (designed specifically for challenging races). 4 | 5 | ## Changelog 6 | 7 | See [the changelog](changelog.md). -------------------------------------------------------------------------------- /example/doc/page-overview.md: -------------------------------------------------------------------------------- 1 | # page `overview` {#overview} 2 | 3 | The `transport` namespace provides several differnt types of bycicles, including [transport::Bicycle](example/doc/api-bicycle.md#classtransport_1_1Bicycle), [transport::MountainBike](example/doc/api-mountainbike.md#classtransport_1_1MountainBike) (designed for rough terrain), and [transport::RacingBike](example/doc/api-racingbike.md#classtransport_1_1RacingBike) (designed specifically for challenging races). 4 | 5 | ## Changelog 6 | 7 | See the changelog. 8 | 9 | -------------------------------------------------------------------------------- /example/xml/combine.xslt: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /example/xml/group__bicycle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | bicycle 5 | Bycicle module 6 | transport::Bicycle 7 | 8 | 9 | 10 | Bicycle module contains the bicycle class. Bicycles are a useful way of transporting oneself, without too much effort. 11 | 12 | 13 | -------------------------------------------------------------------------------- /example/src/racingbike.h: -------------------------------------------------------------------------------- 1 | #ifndef __TRANSPORT_RACING_BIKE_H__ 2 | #define __TRANSPORT_RACING_BIKE_H__ 3 | 4 | #include 5 | 6 | namespace transport 7 | { 8 | /** Racing bike class. 9 | * 10 | * RacingBike is a special kind of bike which can go much faster 11 | * on the road, with much less effort (even uphill!). It doesn't make 12 | * sense to call `RingBell` on a racing bike for they don't have bells. 13 | * 14 | * @ingroup racingbike 15 | */ 16 | class RacingBike : public Bicycle 17 | { 18 | public: 19 | /* @inherit */ 20 | virtual void PedalHarder(); 21 | 22 | /* RingBell is not implemented. */ 23 | virtual void RingBell(); 24 | }; 25 | } 26 | 27 | #endif /* __TRANSPORT_RACING_BIKE_H__ */ 28 | -------------------------------------------------------------------------------- /example/xml/group__mountainbike.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | mountainbike 5 | Mountain bike module 6 | transport::MountainBike 7 | 8 | 9 | 10 | Mountain bike module contains the MountainBike class. Mountain bikes are a kind of bike for cycling on rough terrain. 11 | 12 | 13 | -------------------------------------------------------------------------------- /example/xml/group__racingbike.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | racingbike 5 | Racing bike module 6 | transport::RacingBike 7 | 8 | 9 | 10 | Racing bike module contains the RacingBike class. Racing bikes are a special kind of bike which can go much faster on the road, with much less effort. 11 | 12 | 13 | -------------------------------------------------------------------------------- /example/xml/namespacetransport.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | transport 5 | transport::Bicycle 6 | transport::MountainBike 7 | transport::RacingBike 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /example/xml/changelog.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | changelog 5 | Changelog 6 | 7 | 8 | 9 | Version 1.0.1 10 | 11 | Pedalling harder no longer stands in the saddle by default. This is just better form. 12 | Version 1.0.0 13 | 14 | Initial release 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/markdown.js: -------------------------------------------------------------------------------- 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 | module.exports = { 10 | 11 | refLink: function (text, refid) { 12 | return this.link(text, '{#ref ' + refid + ' #}'); 13 | }, 14 | 15 | link: function (text, href) { 16 | return '[' + text + '](' + href + ')'; 17 | }, 18 | 19 | escape: { 20 | row: function (text) { 21 | return text.replace(/\s*\|\s*$/, ''); 22 | }, 23 | 24 | /** 25 | * Escaping for a cell in a table. 26 | **/ 27 | cell: function (text) { 28 | return text.replace(/^[\n]+|[\n]+$/g, '') // trim CRLF 29 | .replace('/\|/g', '\\|') // escape the pipe 30 | .replace(/\n/g, '
'); // escape CRLF 31 | } 32 | } 33 | 34 | }; 35 | -------------------------------------------------------------------------------- /templates/cpp/index.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | Members | Descriptions 4 | --------------------------------|--------------------------------------------- 5 | {{#each filtered.members}}{{cell proto}} | {{cell summary}} 6 | {{/each}}{{#each filtered.compounds}}{{cell proto}} | {{cell summary}} 7 | {{/each}} 8 | 9 | {{#if filtered.members}} 10 | ## Members 11 | 12 | {{#each filtered.members}} 13 | #### {{title proto}} {{anchor refid}} 14 | 15 | {{briefdescription}} 16 | 17 | {{#if enumvalue}} 18 | Values | Descriptions 19 | --------------------------------|--------------------------------------------- 20 | {{#each enumvalue}}{{cell name}} | {{cell summary}} 21 | {{/each}} 22 | {{/if}} 23 | 24 | {{detaileddescription}} 25 | 26 | {{/each}} 27 | {{/if}} 28 | -------------------------------------------------------------------------------- /example/src/bicycle.h: -------------------------------------------------------------------------------- 1 | #ifndef __TRANSPORT_BICYCLE_H__ 2 | #define __TRANSPORT_BICYCLE_H__ 3 | 4 | namespace transport 5 | { 6 | /** Standard bicycle class. 7 | * 8 | * Bicycle implements a standard bicycle. Bicycles are a useful way of 9 | * transporting oneself, without too much effort (unless you go uphill 10 | * or against the wind). If there are a lot of people on the road, you 11 | * can use `RingBell` to ring your bell (**note**, not all bicycles 12 | * have bells!). 13 | * 14 | * @ingroup bicycle 15 | */ 16 | class Bicycle 17 | { 18 | public: 19 | /// PedalHarder makes you go faster (usually). 20 | virtual void PedalHarder(); 21 | 22 | /** Ring bell on the bike. 23 | * 24 | * RingBell rings the bell on the bike. Note that not all 25 | * bikes have bells. 26 | */ 27 | virtual void RingBell(); 28 | 29 | /// Default destructor. 30 | virtual ~Bicycle(); 31 | }; 32 | } 33 | 34 | #endif /* __TRANSPORT_BICYCLE_H__ */ 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "moxygen", 3 | "version": "0.8.0", 4 | "description": "Doxygen XML to Markdown documentation converter", 5 | "main": "index.js", 6 | "scripts": { 7 | "release": "release-it", 8 | "test": "npm run clean && cd example/ && doxygen && cd .. && node bin/moxygen.js --groups --pages --anchors --output=example/doc/api-%s.md example/xml", 9 | "clean": "rm -rf example/doc/*.md example/xml/" 10 | }, 11 | "bin": { 12 | "moxygen": "./bin/moxygen.js" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/sourcey/moxygen.git" 17 | }, 18 | "keywords": [ 19 | "doxygen", 20 | "markdown", 21 | "documentation", 22 | "generator" 23 | ], 24 | "author": "Kam Low", 25 | "license": "MIT", 26 | "dependencies": { 27 | "commander": "^2.19.0", 28 | "handlebars": "^4.0.12", 29 | "object-assign": "^4.1.1", 30 | "winston": "^3.2.1", 31 | "xml2js": "^0.4.19" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /example/xml/dir_68267d1309a1af8e8297ef4c3efbcdba.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | src 5 | bicycle.cpp 6 | bicycle.h 7 | mountainbike.cpp 8 | mountainbike.h 9 | racingbike.cpp 10 | racingbike.h 11 | transport.h 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /templates/cpp/namespace.md: -------------------------------------------------------------------------------- 1 | # {{kind}} `{{name}}` {{anchor refid}} 2 | 3 | {{briefdescription}} 4 | 5 | {{detaileddescription}} 6 | 7 | ## Summary 8 | 9 | Members | Descriptions 10 | --------------------------------|--------------------------------------------- 11 | {{#each filtered.members}}{{cell proto}} | {{cell summary}} 12 | {{/each}}{{#each filtered.compounds}}{{cell proto}} | {{cell summary}} 13 | {{/each}} 14 | 15 | {{#if filtered.members}} 16 | ## Members 17 | 18 | {{#each filtered.members}} 19 | #### {{title proto}} {{anchor refid}} 20 | 21 | {{#if enumvalue}} 22 | Values | Descriptions 23 | --------------------------------|--------------------------------------------- 24 | {{#each enumvalue}}{{cell name}} | {{cell summary}} 25 | {{/each}} 26 | {{/if}} 27 | 28 | {{briefdescription}} 29 | 30 | {{detaileddescription}} 31 | 32 | {{/each}} 33 | {{/if}} 34 | -------------------------------------------------------------------------------- /templates/cpp/page.md: -------------------------------------------------------------------------------- 1 | # {{kind}} `{{name}}` {{anchor refid}} 2 | 3 | {{briefdescription}} 4 | 5 | {{detaileddescription}} 6 | 7 | {{#if filtered.members}} 8 | 9 | ## Summary 10 | 11 | Members | Descriptions 12 | --------------------------------|--------------------------------------------- 13 | {{#each filtered.members}}{{cell proto}} | {{cell summary}} 14 | {{/each}}{{#each filtered.compounds}}{{cell proto}} | {{cell summary}} 15 | {{/each}} 16 | 17 | ## Members 18 | 19 | {{#each filtered.members}} 20 | #### {{title proto}} {{anchor refid}} 21 | 22 | {{#if enumvalue}} 23 | Values | Descriptions 24 | --------------------------------|--------------------------------------------- 25 | {{#each enumvalue}}{{cell name}} | {{cell summary}} 26 | {{/each}} 27 | {{/if}} 28 | 29 | {{briefdescription}} 30 | 31 | {{detaileddescription}} 32 | 33 | {{/each}} 34 | {{/if}} 35 | -------------------------------------------------------------------------------- /example/xml/overview.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | overview 5 | Transport 6 | 7 | 8 | 9 | The transport namespace provides several differnt types of bycicles, including transport::Bicycle, transport::MountainBike (designed for rough terrain), and transport::RacingBike (designed specifically for challenging races).Changelog 10 | See the changelog. 11 | 12 | 13 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 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. 22 | -------------------------------------------------------------------------------- /example/xml/changelog_8md.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | changelog.md 5 | 6 | 7 | 8 | 9 | 10 | #Changelog{#changelog} 11 | 12 | ##Version1.0.1 13 | 14 | -Pedallinghardernolongerstandsinthesaddlebydefault.Thisisjustbetterform. 15 | 16 | ##Version1.0.0 17 | 18 | -Initialrelease 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /templates/cpp/class.md: -------------------------------------------------------------------------------- 1 | ## {{kind}} `{{name}}` {{anchor refid}} 2 | 3 | {{#if basecompoundref}} 4 | ``` 5 | {{kind}} {{name}} 6 | {{#each basecompoundref}} 7 | : {{prot}} {{name}} 8 | {{/each}} 9 | ``` 10 | {{/if}} 11 | 12 | {{briefdescription}} 13 | 14 | {{detaileddescription}} 15 | 16 | ### Summary 17 | 18 | Members | Descriptions 19 | --------------------------------|--------------------------------------------- 20 | {{#each filtered.compounds}}{{cell proto}} | {{cell summary}} 21 | {{/each}}{{#each filtered.members}}{{cell proto}} | {{cell summary}} 22 | {{/each}} 23 | 24 | ### Members 25 | 26 | {{#each filtered.compounds}} 27 | #### {{title proto}} {{anchor refid}} 28 | 29 | {{briefdescription}} 30 | 31 | {{detaileddescription}} 32 | {{/each}} 33 | 34 | {{#each filtered.members}} 35 | #### {{title proto}} {{anchor refid}} 36 | 37 | {{#if enumvalue}} 38 | Values | Descriptions 39 | --------------------------------|--------------------------------------------- 40 | {{#each enumvalue}}{{cell name}} | {{cell summary}} 41 | {{/each}} 42 | {{/if}} 43 | 44 | {{briefdescription}} 45 | 46 | {{detaileddescription}} 47 | 48 | {{/each}} 49 | -------------------------------------------------------------------------------- /example/xml/overview_8md.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | overview.md 5 | 6 | 7 | 8 | 9 | 10 | #Transport{#overview} 11 | 12 | The`transport`namespaceprovidesseveraldiffernttypesofbycicles,includingtransport::Bicycle,transport::MountainBike(designedforroughterrain),andtransport::RacingBike(designedspecificallyforchallengingraces). 13 | 14 | ##Changelog 15 | 16 | See[thechangelog](changelog.md). 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /example/src/transport.h: -------------------------------------------------------------------------------- 1 | #ifndef __TRANSPORT_H__ 2 | #define __TRANSPORT_H__ 3 | 4 | /** @defgroup bicycle Bycicle module 5 | * 6 | * Bicycle module contains the bicycle class. Bicycles are a useful way of 7 | * transporting oneself, without too much effort. 8 | */ 9 | 10 | #include 11 | 12 | /** @defgroup racingbike Racing bike module 13 | * 14 | * Racing bike module contains the `RacingBike` class. Racing bikes are a 15 | * special kind of bike which can go much faster on the road, with much less 16 | * effort. 17 | */ 18 | 19 | #include 20 | 21 | /** @defgroup mountainbike Mountain bike module 22 | * 23 | * Mountain bike module contains the `MountainBike` class. Mountain bikes are 24 | * a kind of bike for cycling on rough terrain. 25 | */ 26 | 27 | #include 28 | 29 | /** 30 | * Enum class for transport types. 31 | * 32 | * This definition exists in the default namespace and is ungrouped. 33 | * It will *not* be displayed if the `groups` options is used. 34 | */ 35 | enum class TransportType { 36 | Bycicle, /*!< Bycicle type */ 37 | RacingBike, /*!< Racing bike type */ 38 | RacingBike /*!< Mountain bike type */ 39 | }; 40 | 41 | /** 42 | * The modifier value if pedal power is used. 43 | * 44 | * This definition exists in the default namespace and is ungrouped. 45 | * It will *not* be displayed if the `groups` options is used. 46 | */ 47 | #define PEDAL_POWER_MODIFIER 9000 48 | 49 | #endif /* __TRANSPORT_H__ */ 50 | -------------------------------------------------------------------------------- /src/logger.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Original work Copyright (c) 2016 Philippe FERDINAND 3 | * Modified work Copyright (c) 2016 Kam Low 4 | * This file added Copyright (c) 2022 Waldemar Villamayor-Venialbo 5 | * 6 | * @license MIT 7 | **/ 8 | 'use strict'; 9 | 10 | const winston = require('winston'); 11 | 12 | // Create the global logger object 13 | let logger = winston.createLogger({ 14 | level : 'info', 15 | }); 16 | 17 | module.exports = { 18 | 19 | init : function (options, defaultOptions) { 20 | // Logger transports 21 | let logfile = null; 22 | let logterm = null; 23 | 24 | // Create log console transport 25 | logterm = new winston.transports.Console({ 26 | consoleWarnLevels : [ 'warn', 'debug' ], 27 | stderrLevels : [ 'error' ], 28 | silent : options.quiet, 29 | format : winston.format.simple(), 30 | }); 31 | 32 | logger.add(logterm); 33 | 34 | // User defined log file? 35 | if (typeof options.logfile != 'undefined') { 36 | // Use default log file name? 37 | if (options.logfile === true) { 38 | options.logfile = defaultOptions.logfile; 39 | } 40 | // Create log file transport 41 | logfile = new winston.transports.File({ 42 | filename : options.logfile, 43 | level : 'silly', 44 | }); 45 | 46 | logger.add(logfile); 47 | } 48 | 49 | // Set the logging level 50 | if (!options.quiet) { 51 | this.setLevel('verbose'); 52 | } 53 | }, 54 | 55 | getLogger: function () { 56 | return logger; 57 | }, 58 | 59 | setLevel: function (level) { 60 | logger.level = level; 61 | }, 62 | }; 63 | -------------------------------------------------------------------------------- /example/src/mountainbike.h: -------------------------------------------------------------------------------- 1 | #ifndef __TRANSPORT_MOUNTAIN_BIKE_H__ 2 | #define __TRANSPORT_MOUNTAIN_BIKE_H__ 3 | 4 | #include 5 | 6 | namespace transport 7 | { 8 | /** Mountain bike implementation of a `Bicycle`. 9 | * 10 | * MountainBike is an implementation of a Bicycle 11 | * providing a bike for cycling on rough terrain. Mountain bikes 12 | * are pretty cool because they have stuff like **Suspension** (and 13 | * you can even adjust it using SetSuspension). If you're looking 14 | * for a bike for use on the road, you might be better off using a 15 | * RacingBike though. 16 | * 17 | * @ingroup mountainbike 18 | */ 19 | class MountainBike : public Bicycle 20 | { 21 | public: 22 | /** Set suspension stiffness. 23 | * @stiffness the suspension stiffness. 24 | * 25 | * SetSuspension changes the stiffness of the suspension 26 | * on the bike. The method will return false if the stiffness 27 | * could not be adjusted. 28 | * 29 | * @return true if the suspension was adjusted successfully, 30 | * false otherwise. 31 | */ 32 | bool SetSuspension(double stiffness); 33 | 34 | /** Change the break type. 35 | * @BreakType the break type. 36 | * @breakType the type of the break. 37 | * 38 | * ChangesBreak changes the type of break fitted to the bike. 39 | * The method will return false if the break type could not be 40 | * fitted. 41 | * 42 | * @return true if the break was adjusted successfully. 43 | * false otherise 44 | */ 45 | template 46 | bool ChangeBreak(BreakType breakType) 47 | { 48 | if (breakType) 49 | { 50 | return true; 51 | } 52 | 53 | return false; 54 | } 55 | }; 56 | } 57 | 58 | #endif /* __TRANSPORT_MOUNTAIN_BIKE_H__ */ 59 | -------------------------------------------------------------------------------- /bin/moxygen.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict'; 3 | 4 | var logger = require('../src/logger'); 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] ') 12 | .option('-o, --output ', 'output file, must contain "%s" when using `groups` or `classes` (default: "api.md"/"api_%s.md")', String) 13 | .option('-g, --groups', 'output doxygen groups into separate files', false) 14 | .option('-c, --classes', 'output doxygen classes into separate files', false) 15 | .option('-p, --pages', 'output doxygen pages into separate files', false) 16 | .option('-n, --noindex', 'disable generation of the index, ignored with `groups` or `classes`', false) 17 | .option('-a, --anchors', 'add anchors to internal links', false) 18 | .option('-H, --html-anchors', 'add html anchors to internal links', false) 19 | .option('-l, --language ', 'programming language', String, 'cpp') 20 | .option('-t, --templates ', 'custom templates directory (default: "built-in templates")', String) 21 | .option('-L, --logfile [file]', 'output log messages to file, (default: console only, default file name: "moxygen.log")') 22 | .option('-q, --quiet', 'quiet mode', false) 23 | .parse(process.argv); 24 | 25 | logger.init(program, app.defaultOptions); 26 | 27 | if (program.args.length) { 28 | app.run(assign({}, app.defaultOptions, { 29 | directory: program.args[0], 30 | output: program.output, 31 | groups: program.groups, 32 | pages: program.pages, 33 | classes: program.classes, 34 | noindex: program.noindex, 35 | anchors: program.anchors, 36 | htmlAnchors: program.htmlAnchors, 37 | language: program.language, 38 | templates: program.templates, 39 | })); 40 | } 41 | else { 42 | program.help(); 43 | } 44 | -------------------------------------------------------------------------------- /example/doc/api-racingbike.md: -------------------------------------------------------------------------------- 1 | # group `racingbike` {#group__racingbike} 2 | 3 | Racing bike module contains the `RacingBike` class. Racing bikes are a special kind of bike which can go much faster on the road, with much less effort. 4 | 5 | ## Summary 6 | 7 | Members | Descriptions 8 | --------------------------------|--------------------------------------------- 9 | `class `[`transport::RacingBike`](#classtransport_1_1RacingBike) | Racing bike class. 10 | 11 | # class `transport::RacingBike` {#classtransport_1_1RacingBike} 12 | 13 | ``` 14 | class transport::RacingBike 15 | : public transport::Bicycle 16 | ``` 17 | 18 | Racing bike class. 19 | 20 | [RacingBike](#classtransport_1_1RacingBike) is a special kind of bike which can go much faster on the road, with much less effort (even uphill!). It doesn't make sense to call `RingBell` on a racing bike for they don't have bells. 21 | 22 | ## Summary 23 | 24 | Members | Descriptions 25 | --------------------------------|--------------------------------------------- 26 | `public virtual void `[`PedalHarder`](#classtransport_1_1RacingBike_1ab557c5727daa07a5001782d5dcd46c5b)`()` | PedalHarder makes you go faster (usually). 27 | `public virtual void `[`RingBell`](#classtransport_1_1RacingBike_1ad32dc3b06a453fba3e20329842bb318b)`()` | Ring bell on the bike. 28 | 29 | ## Members 30 | 31 | #### `public virtual void `[`PedalHarder`](#classtransport_1_1RacingBike_1ab557c5727daa07a5001782d5dcd46c5b)`()` {#classtransport_1_1RacingBike_1ab557c5727daa07a5001782d5dcd46c5b} 32 | 33 | PedalHarder makes you go faster (usually). 34 | 35 | #### `public virtual void `[`RingBell`](#classtransport_1_1RacingBike_1ad32dc3b06a453fba3e20329842bb318b)`()` {#classtransport_1_1RacingBike_1ad32dc3b06a453fba3e20329842bb318b} 36 | 37 | Ring bell on the bike. 38 | 39 | RingBell rings the bell on the bike. Note that not all bikes have bells. 40 | 41 | -------------------------------------------------------------------------------- /example/doc/api-bicycle.md: -------------------------------------------------------------------------------- 1 | # group `bicycle` {#group__bicycle} 2 | 3 | Bicycle module contains the bicycle class. Bicycles are a useful way of transporting oneself, without too much effort. 4 | 5 | ## Summary 6 | 7 | Members | Descriptions 8 | --------------------------------|--------------------------------------------- 9 | `class `[`transport::Bicycle`](#classtransport_1_1Bicycle) | Standard bicycle class. 10 | 11 | # class `transport::Bicycle` {#classtransport_1_1Bicycle} 12 | 13 | Standard bicycle class. 14 | 15 | [Bicycle](#classtransport_1_1Bicycle) implements a standard bicycle. Bicycles are a useful way of transporting oneself, without too much effort (unless you go uphill or against the wind). If there are a lot of people on the road, you can use `RingBell` to ring your bell (**note**, not all bicycles have bells!). 16 | 17 | ## Summary 18 | 19 | Members | Descriptions 20 | --------------------------------|--------------------------------------------- 21 | `public virtual void `[`PedalHarder`](#classtransport_1_1Bicycle_1a7df6cce8f18012fb07bef5be9dadd8ef)`()` | PedalHarder makes you go faster (usually). 22 | `public virtual void `[`RingBell`](#classtransport_1_1Bicycle_1a7d2be572f09c78b4d4ae38ef22f3e98b)`()` | Ring bell on the bike. 23 | `public virtual `[`~Bicycle`](#classtransport_1_1Bicycle_1a5f62d09b772a7705634bfb3551803c25)`()` | Default destructor. 24 | 25 | ## Members 26 | 27 | #### `public virtual void `[`PedalHarder`](#classtransport_1_1Bicycle_1a7df6cce8f18012fb07bef5be9dadd8ef)`()` {#classtransport_1_1Bicycle_1a7df6cce8f18012fb07bef5be9dadd8ef} 28 | 29 | PedalHarder makes you go faster (usually). 30 | 31 | #### `public virtual void `[`RingBell`](#classtransport_1_1Bicycle_1a7d2be572f09c78b4d4ae38ef22f3e98b)`()` {#classtransport_1_1Bicycle_1a7d2be572f09c78b4d4ae38ef22f3e98b} 32 | 33 | Ring bell on the bike. 34 | 35 | RingBell rings the bell on the bike. Note that not all bikes have bells. 36 | 37 | #### `public virtual `[`~Bicycle`](#classtransport_1_1Bicycle_1a5f62d09b772a7705634bfb3551803c25)`()` {#classtransport_1_1Bicycle_1a5f62d09b772a7705634bfb3551803c25} 38 | 39 | Default destructor. 40 | 41 | -------------------------------------------------------------------------------- /example/xml/mountainbike_8cpp.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | mountainbike.cpp 5 | mountainbike.h 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | #include"mountainbike.h" 29 | 30 | usingnamespacetransport; 31 | 32 | bool 33 | MountainBike::SetSuspension(doublestiffness) 34 | { 35 | returntrue; 36 | } 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /example/xml/index.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /example/xml/racingbike_8cpp.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | racingbike.cpp 5 | racingbike.h 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | #include"racingbike.h" 29 | 30 | usingnamespacetransport; 31 | 32 | void 33 | RacingBike::RingBell() 34 | { 35 | } 36 | 37 | void 38 | RacingBike::PedalHarder() 39 | { 40 | } 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /example/doc/api-mountainbike.md: -------------------------------------------------------------------------------- 1 | # group `mountainbike` {#group__mountainbike} 2 | 3 | Mountain bike module contains the `MountainBike` class. Mountain bikes are a kind of bike for cycling on rough terrain. 4 | 5 | ## Summary 6 | 7 | Members | Descriptions 8 | --------------------------------|--------------------------------------------- 9 | `class `[`transport::MountainBike`](#classtransport_1_1MountainBike) | Mountain bike implementation of a `[Bicycle](example/doc/api-bicycle.md#classtransport_1_1Bicycle)`. 10 | 11 | # class `transport::MountainBike` {#classtransport_1_1MountainBike} 12 | 13 | ``` 14 | class transport::MountainBike 15 | : public transport::Bicycle 16 | ``` 17 | 18 | Mountain bike implementation of a `[Bicycle](example/doc/api-bicycle.md#classtransport_1_1Bicycle)`. 19 | 20 | [MountainBike](#classtransport_1_1MountainBike) is an implementation of a [Bicycle](example/doc/api-bicycle.md#classtransport_1_1Bicycle) providing a bike for cycling on rough terrain. Mountain bikes are pretty cool because they have stuff like **Suspension** (and you can even adjust it using SetSuspension). If you're looking for a bike for use on the road, you might be better off using a [RacingBike](example/doc/api-racingbike.md#classtransport_1_1RacingBike) though. 21 | 22 | ## Summary 23 | 24 | Members | Descriptions 25 | --------------------------------|--------------------------------------------- 26 | `public bool `[`SetSuspension`](#classtransport_1_1MountainBike_1a04caecd7e5ff7572b6ac1dc283510301)`(double stiffness)` | Set suspension stiffness. the suspension stiffness. 27 | `public template<>`
`inline bool `[`ChangeBreak`](#classtransport_1_1MountainBike_1afd02513876a196e98acaacdc555aeb52)`(BreakType breakType)` | Change the break type. the break type. the type of the break. 28 | 29 | ## Members 30 | 31 | #### `public bool `[`SetSuspension`](#classtransport_1_1MountainBike_1a04caecd7e5ff7572b6ac1dc283510301)`(double stiffness)` {#classtransport_1_1MountainBike_1a04caecd7e5ff7572b6ac1dc283510301} 32 | 33 | Set suspension stiffness. the suspension stiffness. 34 | 35 | SetSuspension changes the stiffness of the suspension on the bike. The method will return false if the stiffness could not be adjusted. 36 | 37 | #### Returns 38 | true if the suspension was adjusted successfully, false otherwise. 39 | 40 | #### `public template<>`
`inline bool `[`ChangeBreak`](#classtransport_1_1MountainBike_1afd02513876a196e98acaacdc555aeb52)`(BreakType breakType)` {#classtransport_1_1MountainBike_1afd02513876a196e98acaacdc555aeb52} 41 | 42 | Change the break type. the break type. the type of the break. 43 | 44 | ChangesBreak changes the type of break fitted to the bike. The method will return false if the break type could not be fitted. 45 | 46 | #### Returns 47 | true if the break was adjusted successfully. false otherise 48 | 49 | -------------------------------------------------------------------------------- /example/xml/bicycle_8cpp.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | bicycle.cpp 5 | bicycle.h 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | #include"bicycle.h" 24 | 25 | usingnamespacetransport; 26 | 27 | Bicycle::~Bicycle() 28 | { 29 | } 30 | 31 | void 32 | Bicycle::RingBell() 33 | { 34 | } 35 | 36 | void 37 | Bicycle::PedalHarder() 38 | { 39 | } 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/templates.js: -------------------------------------------------------------------------------- 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 log = require('./logger').getLogger(); 11 | var path = require('path'); 12 | var handlebars = require('handlebars'); 13 | // var tidyMarkdown = require('tidy-markdown'); 14 | 15 | var doxyparser = require('./parser'); 16 | var helpers = require('./helpers'); 17 | var markdown = require('./markdown'); 18 | 19 | module.exports = { 20 | 21 | // Loaded templates 22 | templates: {}, 23 | 24 | // Load templates from the given directory 25 | load: function (templateDirectory) { 26 | fs.readdirSync(templateDirectory).forEach(function (filename) { 27 | var fullname = path.join(templateDirectory, filename); 28 | var template = handlebars.compile(fs.readFileSync(fullname, 'utf8'), { 29 | noEscape: true, 30 | strict: true 31 | }); 32 | this.templates[filename.match(/(.*)\.md$/)[1]] = template; 33 | }.bind(this)); 34 | }, 35 | 36 | render: function (compound) { 37 | var template; 38 | 39 | log.verbose('Rendering ' + compound.kind + ' ' + compound.fullname); 40 | 41 | switch (compound.kind) { 42 | case 'index': 43 | template = 'index'; 44 | break; 45 | case 'page': 46 | template = 'page' 47 | break; 48 | case 'group': 49 | case 'namespace': 50 | if (Object.keys(compound.compounds).length === 1 51 | && compound.compounds[Object.keys(compound.compounds)[0]].kind == 'namespace') { 52 | return undefined; 53 | } 54 | template = 'namespace'; 55 | break; 56 | case 'class': 57 | case 'struct': 58 | case 'interface': 59 | template = 'class'; 60 | break; 61 | default: 62 | log.warn('Cannot render ' + compound.kind + ' ' + compound.fullname); 63 | console.log('Skipping ', compound); 64 | return undefined; 65 | } 66 | 67 | if (typeof this.templates[template] == "undefined") { 68 | throw 'Template "' + template + '" not found in your templates directory.'; 69 | } 70 | 71 | return this.templates[template](compound).replace(/(\r\n|\r|\n){3,}/g, '$1\n'); 72 | }, 73 | 74 | renderArray: function (compounds) { 75 | return compounds.map(function(compound) { 76 | return this.render(compound); 77 | }.bind(this)); 78 | }, 79 | 80 | // Register handlebars helpers 81 | registerHelpers: function (options) { 82 | 83 | // Escape the code for a table cell. 84 | handlebars.registerHelper('cell', function(code) { 85 | return code.replace(/\|/g, '\\|').replace(/\n/g, '
'); 86 | }); 87 | 88 | // Escape the code for a titles. 89 | handlebars.registerHelper('title', function(code) { 90 | return code.replace(/\n/g, '
'); 91 | }); 92 | 93 | // Generate an anchor for internal links 94 | handlebars.registerHelper('anchor', function(name) { 95 | return helpers.getAnchor(name, options); 96 | }); 97 | }, 98 | }; 99 | -------------------------------------------------------------------------------- /src/compound.js: -------------------------------------------------------------------------------- 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('./logger').getLogger(); 10 | 11 | function Compound(parent, id, name) { 12 | this.parent = parent; 13 | this.id = id; 14 | this.name = name; 15 | this.compounds = {}; 16 | this.members = []; 17 | this.basecompoundref = []; 18 | this.filtered = {}; 19 | } 20 | 21 | Compound.prototype = { 22 | 23 | find: function (id, name, create) { 24 | var compound = this.compounds[id]; 25 | 26 | if (!compound && create) { 27 | compound = this.compounds[id] = new Compound(this, id, name); 28 | } 29 | 30 | return compound; 31 | }, 32 | 33 | toArray: function (type, kind) { 34 | type = type || 'compounds'; 35 | var arr = Object.keys(this[type]).map(function(key) { 36 | return this[key]; 37 | }.bind(this[type])); 38 | 39 | if (type == 'compounds') { 40 | var all = new Array(); 41 | arr.forEach(function (compound) { 42 | if (!kind || compound.kind == kind) { //compound && 43 | all.push(compound); 44 | all = all.concat(compound.toArray(type, kind)); 45 | } 46 | }.bind(this)); 47 | arr = all; 48 | } 49 | 50 | return arr; 51 | }, 52 | 53 | toFilteredArray: function (type) { 54 | type = type || 'compounds'; 55 | var all = []; 56 | 57 | (this.filtered[type] || []).forEach(function (item) { 58 | var children = item.toFilteredArray(type); 59 | all.push(item); 60 | all = all.concat(children); 61 | }); 62 | 63 | return all; 64 | }, 65 | 66 | filterChildren: function (filters, groupid) { 67 | this.toArray('compounds').forEach(function (compound) { 68 | compound.filtered.members = compound.filter(compound.members, 'section', filters.members, groupid); 69 | compound.filtered.compounds = compound.filter(compound.compounds, 'kind', filters.compounds, groupid); 70 | }); 71 | this.filtered.members = this.filter(this.members, 'section', filters.members, groupid); 72 | this.filtered.compounds = this.filter(this.compounds, 'kind', filters.compounds, groupid); 73 | }, 74 | 75 | filter: function (collection, key, filter, groupid) { 76 | var categories = {}; 77 | var result = []; 78 | 79 | Object.keys(collection).forEach(function (name) { 80 | var item = collection[name]; 81 | if (item) { 82 | 83 | // skip empty namespaces 84 | if (item.kind == 'namespace') { 85 | if ((!item.filtered.compounds || !item.filtered.compounds.length) && 86 | (!item.filtered.members || !item.filtered.members.length)) { 87 | // log.verbose('Skip empty namespace: ' + item.name); 88 | return; 89 | } 90 | } 91 | 92 | // skip items not belonging to current group 93 | else if (groupid && item.groupid != groupid) { 94 | // log.verbose('Skip item from foreign group: { item.kind: ' + item.kind 95 | // + ', item.name: ' + item.name + ', item.groupid: ' 96 | // + item.groupid + ', group.id: '+ group.id + '}'); 97 | return; 98 | } 99 | 100 | (categories[item[key]] || (categories[item[key]] = [])).push(item); 101 | } 102 | }.bind(this)); 103 | 104 | filter.forEach(function (category) { 105 | result = result.concat(categories[category] || []); 106 | }); 107 | 108 | return result; 109 | }, 110 | } 111 | 112 | module.exports = Compound; 113 | -------------------------------------------------------------------------------- /example/xml/index.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | transport::Bicycle 4 | PedalHarder 5 | RingBell 6 | ~Bicycle 7 | 8 | transport::MountainBike 9 | SetSuspension 10 | ChangeBreak 11 | 12 | transport::RacingBike 13 | PedalHarder 14 | RingBell 15 | 16 | transport 17 | 18 | bicycle.cpp 19 | 20 | bicycle.h 21 | 22 | changelog.md 23 | 24 | mountainbike.cpp 25 | 26 | mountainbike.h 27 | 28 | overview.md 29 | 30 | racingbike.cpp 31 | 32 | racingbike.h 33 | 34 | transport.h 35 | PEDAL_POWER_MODIFIER 36 | TransportType 37 | Bycicle 38 | RacingBike 39 | RacingBike 40 | 41 | bicycle 42 | 43 | racingbike 44 | 45 | mountainbike 46 | 47 | changelog 48 | 49 | overview 50 | 51 | src 52 | 53 | 54 | -------------------------------------------------------------------------------- /example/xml/bicycle_8h.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | bicycle.h 5 | src/bicycle.cpp 6 | transport::Bicycle 7 | transport 8 | 9 | 10 | 11 | 12 | 13 | #ifndef__TRANSPORT_BICYCLE_H__ 14 | #define__TRANSPORT_BICYCLE_H__ 15 | 16 | namespacetransport 17 | { 18 | classBicycle 19 | { 20 | public: 21 | virtualvoidPedalHarder(); 22 | 23 | virtualvoidRingBell(); 24 | 25 | virtual~Bicycle(); 26 | }; 27 | } 28 | 29 | #endif/*__TRANSPORT_BICYCLE_H__*/ 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Moxygen 2 | 3 | Moxygen is a Doxygen XML to Markdown converter for C++ developers who want a minimal and beautiful solution for documentating their projects. 4 | 5 | Moxygen is currently used in conjunction with GitBook to generate the API documentation for [LibSourcey](http://sourcey.com/libsourcey/). 6 | 7 | ## Features 8 | 9 | * **Multi page output**: Output single or multiple files 10 | * **Internal linking**: Anchors in comments and function definitions are supported 11 | * **Markdown comments**: Markdown in Doxygen comments are rendered 12 | * **Doxygen groups**: Doxygen [grouping](http://www.doxygen.nl/manual/grouping.html) is supported for more organised documentation 13 | * **Custom templates**: Modify the core Markdown templates to add your own flavour 14 | * **Optional index**: Optionally render a top level index 15 | 16 | ## Usage 17 | 18 | 1. Add `GENERATE_XML=YES` to your `Doxyfile` first. 19 | 2. Run `doxygen` to generate the XML documentation. 20 | 3. Install `moxygen` like so: `npm install moxygen -g`. 21 | 4. Run `moxygen` providing the folder location of the XML documentation as the first argument ie. `{OUTPUT_DIRECTORY}/xml`. 22 | ``` 23 | Usage: moxygen [options] 24 | 25 | Options: 26 | 27 | -V, --version output the version number 28 | -o, --output output file, must contain "%s" when using `groups` or `classes` 29 | -g, --groups output doxygen groups into separate files 30 | -c, --classes output doxygen classes into separate files 31 | -p, --pages output doxygen pages into separate files 32 | -n, --noindex disable generation of the index, ignored with `groups` or `classes` 33 | -a, --anchors add anchors to internal links 34 | -H, --html-anchors add html anchors to internal links 35 | -l, --language programming language 36 | -t, --templates custom templates directory 37 | -L, --logfile [file] output log messages to file 38 | -q, --quiet quiet mode 39 | -h, --help output usage information 40 | ``` 41 | 42 | ## Multi-page Output 43 | 44 | Moxygen supports the doxygen [groups](http://www.doxygen.nl/manual/grouping.html#modules) syntax for generating multi page documentation. Every [\defgroup](http://www.doxygen.nl/manual/commands.html#cmddefgroup) in your source code will be parsed and output into a separate markdown file, with internal reference updated accordingly. 45 | 46 | Example: 47 | 48 | ``` 49 | moxygen --anchors --groups --output api-%s.md /path/to/doxygen/xml 50 | ``` 51 | 52 | ## Example 53 | 54 | To get a feel for how Moxygen works you can play with the example which is located in the [example](/example) folder. The example contains: 55 | 56 | * Documented C++ example code 57 | * A `Doxyfile` file (for doxygen 1.8.13) 58 | * Pre-generated XML output in [example/xml](/example/xml) 59 | * Pre-generated output Markdown files in [example/doc](/example/doc) 60 | 61 | To fully build the example, follow these steps (once you've installed `doxygen`. See **Development & Contribution**, below): 62 | 63 | 1. Rebuild the XML: run `doxygen` from within the example folder. 64 | 2. Rebuild the Moxygen output: from within this directory, 65 | 66 | ``` 67 | node bin/moxygen.js --groups --pages --anchors --output=example/doc/api-%s.md example/xml 68 | ``` 69 | 70 | ## Development & Contribution 71 | 72 | You can develop this project as you would any other Node project: 73 | 74 | 1. Clone this repo. 75 | 2. `npm install` from this directory. 76 | 77 | This project is tested through integration, by building the `example/`. To quickly test this project: 78 | 79 | 1. Install `doxygen` (`brew install doxygen`, `choco install doxygen`, for example). Only must be done once per computer. 80 | 2. `npm test` from this directory. This will run Doxygen on the `example/` and build the output. 81 | -------------------------------------------------------------------------------- /src/helpers.js: -------------------------------------------------------------------------------- 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 log = require('./logger').getLogger(); 13 | var handlebars = require('handlebars'); 14 | 15 | module.exports = { 16 | 17 | inline: function(code) { 18 | if (Array.isArray(code)) { 19 | var refs, s = '', isInline = false; 20 | code.forEach(function (e) { 21 | refs = e.split(/(\[.*\]\(.*\)|\n|\s{2}\n)/g); 22 | refs.forEach(function (f) { 23 | if (f.charAt(0) == '[') { 24 | // link 25 | var link = f.match(/\[(.*)\]\((.*)\)/); 26 | if (link) { 27 | isInline ? (s += '`') && (isInline = false) : null; 28 | s += '[`' + link[1] + '`](' + link[2] + ')'; 29 | } 30 | } 31 | else if (f == '\n' || f == ' \n') { 32 | // line break 33 | isInline ? (s += '`') && (isInline = false) : null; 34 | s += f; 35 | } 36 | else if (f) { 37 | !isInline ? (s += '`') && (isInline = true) : null; 38 | s += f; 39 | } 40 | }); 41 | }); 42 | return s + (isInline ? '`' : ''); 43 | } 44 | else { 45 | return '`' + code + '`'; 46 | } 47 | }, 48 | 49 | getAnchor: function(name, options) { 50 | if (options.anchors) { 51 | return '{#' + name + '}'; 52 | } 53 | else if (options.htmlAnchors) { 54 | return ''; 55 | } 56 | else { 57 | return ''; 58 | } 59 | }, 60 | 61 | findParent: function(compound, kinds) { 62 | while (compound) { 63 | if (kinds.includes(compound.kind)) 64 | return compound; 65 | compound = compound.parent; 66 | } 67 | }, 68 | 69 | // Replace ref links to point to correct output file if needed 70 | resolveRefs: function(content, compound, references, options) { 71 | return content.replace(/\{#ref ([^ ]+) #\}/g, function(_, refid) { 72 | var ref = references[refid] 73 | var page = this.findParent(ref, ['page']); 74 | 75 | if (page) { 76 | if (page.refid == compound.refid) 77 | return '#' + refid; 78 | return this.compoundPath(page, options) + '#' + refid; 79 | } 80 | 81 | if (options.groups) { 82 | if (compound.groupid && compound.groupid == ref.groupid) 83 | return '#' + refid; 84 | return this.compoundPath(ref, options) + '#' + refid; 85 | } else if (options.classes) { 86 | var dest = this.findParent(ref, ['namespace', 'class', 'struct']); 87 | if (!dest || compound.refid == dest.refid) 88 | return '#' + refid; 89 | return this.compoundPath(dest, options) + '#' + refid; 90 | } else { 91 | if (compound.kind == 'page') 92 | return this.compoundPath(compound.parent, options) + '#' + refid; 93 | return '#' + refid; 94 | } 95 | }.bind(this)); 96 | }, 97 | 98 | compoundPath: function(compound, options) { 99 | if (compound.kind == 'page') { 100 | return path.dirname(options.output) + "/page-" + compound.name + ".md"; 101 | } else if (options.groups) { 102 | return util.format(options.output, compound.groupname); 103 | } else if (options.classes) { 104 | return util.format(options.output, compound.name.replace(/\:/g, '-').replace('<', '(').replace('>', ')')); 105 | } else { 106 | return options.output; 107 | } 108 | }, 109 | 110 | writeCompound: function(compound, contents, references, options) { 111 | this.writeFile(this.compoundPath(compound, options), contents.map(function(content) { 112 | return this.resolveRefs(content, compound, references, options); 113 | }.bind(this))); 114 | }, 115 | 116 | // Write the output file 117 | writeFile: function (filepath, contents) { 118 | log.verbose('Writing: ' + filepath); 119 | var stream = fs.createWriteStream(filepath); 120 | stream.once('open', function(fd) { 121 | contents.forEach(function (content) { 122 | if (content) 123 | stream.write(content); 124 | }); 125 | stream.end(); 126 | }); 127 | }, 128 | }; 129 | -------------------------------------------------------------------------------- /example/xml/classtransport_1_1RacingBike.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | transport::RacingBike 5 | transport::Bicycle 6 | racingbike.h 7 | 8 | 9 | void 10 | void RacingBike::PedalHarder 11 | () 12 | PedalHarder 13 | PedalHarder 14 | 15 | PedalHarder makes you go faster (usually). 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | void 24 | void RacingBike::RingBell 25 | () 26 | RingBell 27 | RingBell 28 | 29 | 30 | 31 | Ring bell on the bike.RingBell rings the bell on the bike. Note that not all bikes have bells. 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | Racing bike class.RacingBike is a special kind of bike which can go much faster on the road, with much less effort (even uphill!). It doesn't make sense to call RingBell on a racing bike for they don't have bells. 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | transport::RacingBikePedalHarder 68 | transport::RacingBikeRingBell 69 | transport::RacingBike~Bicycle 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /example/xml/racingbike_8h.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | racingbike.h 5 | transport/bicycle.h 6 | src/racingbike.cpp 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | transport::RacingBike 19 | transport 20 | 21 | 22 | 23 | 24 | 25 | #ifndef__TRANSPORT_RACING_BIKE_H__ 26 | #define__TRANSPORT_RACING_BIKE_H__ 27 | 28 | #include<transport/bicycle.h> 29 | 30 | namespacetransport 31 | { 32 | classRacingBike:publicBicycle 33 | { 34 | public: 35 | /*@inherit*/ 36 | virtualvoidPedalHarder(); 37 | 38 | /*RingBellisnotimplemented.*/ 39 | virtualvoidRingBell(); 40 | }; 41 | } 42 | 43 | #endif/*__TRANSPORT_RACING_BIKE_H__*/ 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /example/xml/classtransport_1_1Bicycle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | transport::Bicycle 5 | transport::MountainBike 6 | transport::RacingBike 7 | bicycle.h 8 | 9 | 10 | void 11 | void Bicycle::PedalHarder 12 | () 13 | PedalHarder 14 | PedalHarder 15 | 16 | PedalHarder makes you go faster (usually). 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | void 25 | void Bicycle::RingBell 26 | () 27 | RingBell 28 | RingBell 29 | 30 | 31 | 32 | Ring bell on the bike.RingBell rings the bell on the bike. Note that not all bikes have bells. 33 | 34 | 35 | 36 | 37 | 38 | 39 | Bicycle::~Bicycle 40 | () 41 | ~Bicycle 42 | 43 | Default destructor. 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | Standard bicycle class.Bicycle implements a standard bicycle. Bicycles are a useful way of transporting oneself, without too much effort (unless you go uphill or against the wind). If there are a lot of people on the road, you can use RingBell to ring your bell (note, not all bicycles have bells!). 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | transport::BicyclePedalHarder 76 | transport::BicycleRingBell 77 | transport::Bicycle~Bicycle 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 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 | 11 | var doxyparser = require('./src/parser'); 12 | var templates = require('./src/templates'); 13 | var helpers = require('./src/helpers'); 14 | 15 | module.exports = { 16 | 17 | /** 18 | * Default options values. 19 | **/ 20 | defaultOptions: { 21 | 22 | directory: null, /** Location of the doxygen files **/ 23 | output: 'api.md', /** Output file **/ 24 | groups: false, /** Output doxygen groups separately **/ 25 | noindex: false, /** Disable generation of the index. Does not work with `groups` option **/ 26 | anchors: true, /** Generate anchors for internal links **/ 27 | language: 'cpp', /** Programming language **/ 28 | templates: 'templates', /** Templates directory **/ 29 | pages: false, /** Output doxygen pages separately **/ 30 | classes: false, /** Output doxygen classes separately **/ 31 | output_s: 'api_%s.md', /** Output file for groups and classes **/ 32 | logfile: 'moxygen.log', /** Log file **/ 33 | 34 | filters: { 35 | members: [ 36 | 'define', 37 | 'enum', 38 | // 'enumvalue', 39 | 'func', 40 | // 'variable', 41 | 'property', 42 | 'public-attrib', 43 | 'public-func', 44 | 'protected-attrib', 45 | 'protected-func', 46 | 'signal', 47 | 'public-slot', 48 | 'protected-slot', 49 | 'public-type', 50 | 'private-attrib', 51 | 'private-func', 52 | 'private-slot', 53 | 'public-static-func', 54 | 'private-static-func', 55 | ], 56 | compounds: [ 57 | 'namespace', 58 | 'class', 59 | 'struct', 60 | 'union', 61 | 'typedef', 62 | 'interface', 63 | // 'file', 64 | ] 65 | }, 66 | }, 67 | 68 | /** 69 | * Parse files and render the output. 70 | **/ 71 | run: function (options) { 72 | 73 | // Sanitize options 74 | if (typeof options.output == "undefined") { 75 | if (options.classes || options.groups) { 76 | options.output = this.defaultOptions.output_s; 77 | } 78 | else { 79 | options.output = this.defaultOptions.output; 80 | } 81 | } 82 | 83 | if ((options.classes || options.groups) && options.output.indexOf('%s') === -1) { 84 | throw "The `output` file parameter must contain an '%s' for group or class name " + 85 | "substitution when `groups` or `classes` are enabled." 86 | } 87 | 88 | if (typeof options.templates == "undefined") { 89 | options.templates = path.join(__dirname, this.defaultOptions.templates, options.language); 90 | } 91 | 92 | // Load templates 93 | templates.registerHelpers(options); 94 | templates.load(options.templates); 95 | 96 | // Parse files 97 | doxyparser.loadIndex(options, function (err, root) { 98 | if (err) 99 | throw err; 100 | // Output groups 101 | if (options.groups) { 102 | var groups = root.toArray('compounds', 'group'); 103 | if (!groups.length) 104 | throw "You have enabled `groups` output, but no groups were " + 105 | "located in your doxygen XML files." 106 | 107 | groups.forEach(function (group) { 108 | group.filterChildren(options.filters, group.id); 109 | 110 | var compounds = group.toFilteredArray('compounds'); 111 | compounds.unshift(group); // insert group at top 112 | helpers.writeCompound(group, templates.renderArray(compounds), doxyparser.references, options); 113 | }); 114 | } 115 | else if (options.classes) { 116 | var rootCompounds = root.toArray('compounds', 'namespace'); 117 | if (!rootCompounds.length) 118 | throw "You have enabled `classes` output, but no classes were " + 119 | "located in your doxygen XML files." 120 | rootCompounds.forEach(function (comp) { 121 | comp.filterChildren(options.filters); 122 | var compounds = comp.toFilteredArray(); 123 | helpers.writeCompound(comp, [templates.render(comp)], doxyparser.references, options); 124 | compounds.forEach(function (e) { 125 | e.filterChildren(options.filters) 126 | helpers.writeCompound(e, [templates.render(e)], doxyparser.references, options); 127 | }); 128 | }); 129 | } 130 | // Output single file 131 | else { 132 | root.filterChildren(options.filters); 133 | 134 | var compounds = root.toFilteredArray('compounds'); 135 | if (!options.noindex) 136 | compounds.unshift(root); // insert root at top if index is enabled 137 | var contents = templates.renderArray(compounds); 138 | contents.push('Generated by [Moxygen](https://sourcey.com/moxygen)') 139 | helpers.writeCompound(root, contents, doxyparser.references, options); 140 | } 141 | 142 | if(options.pages){ 143 | var pages = root.toArray('compounds', 'page'); 144 | if(!pages.length) 145 | throw "You have enabled `pages` output, but no pages were " + 146 | "located in your doxygen XML files." 147 | pages.forEach(function(page){ 148 | var compounds = page.toFilteredArray('compounds'); 149 | compounds.unshift(page); 150 | helpers.writeCompound(page, templates.renderArray(compounds), doxyparser.references, options); 151 | }) 152 | } 153 | 154 | }); 155 | }, 156 | } 157 | -------------------------------------------------------------------------------- /example/xml/classtransport_1_1MountainBike.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | transport::MountainBike 5 | transport::Bicycle 6 | mountainbike.h 7 | 8 | 9 | bool 10 | bool MountainBike::SetSuspension 11 | (double stiffness) 12 | SetSuspension 13 | 14 | double 15 | stiffness 16 | 17 | 18 | 19 | 20 | Set suspension stiffness. the suspension stiffness.SetSuspension changes the stiffness of the suspension on the bike. The method will return false if the stiffness could not be adjusted.true if the suspension was adjusted successfully, false otherwise. 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | typename BreakType 30 | 31 | 32 | bool 33 | bool transport::MountainBike::ChangeBreak 34 | (BreakType breakType) 35 | ChangeBreak 36 | 37 | BreakType 38 | breakType 39 | 40 | 41 | 42 | 43 | Change the break type. the break type. the type of the break.ChangesBreak changes the type of break fitted to the bike. The method will return false if the break type could not be fitted.true if the break was adjusted successfully. false otherise 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | Mountain bike implementation of a Bicycle.MountainBike is an implementation of a Bicycle providing a bike for cycling on rough terrain. Mountain bikes are pretty cool because they have stuff like Suspension (and you can even adjust it using SetSuspension). If you're looking for a bike for use on the road, you might be better off using a RacingBike though. 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | transport::MountainBikeChangeBreak 81 | transport::MountainBikePedalHarder 82 | transport::MountainBikeRingBell 83 | transport::MountainBikeSetSuspension 84 | transport::MountainBike~Bicycle 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /example/xml/mountainbike_8h.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | mountainbike.h 5 | transport/bicycle.h 6 | src/mountainbike.cpp 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | transport::MountainBike 19 | transport 20 | 21 | 22 | 23 | 24 | 25 | #ifndef__TRANSPORT_MOUNTAIN_BIKE_H__ 26 | #define__TRANSPORT_MOUNTAIN_BIKE_H__ 27 | 28 | #include<transport/bicycle.h> 29 | 30 | namespacetransport 31 | { 32 | classMountainBike:publicBicycle 33 | { 34 | public: 35 | boolSetSuspension(doublestiffness); 36 | 37 | template<typenameBreakType> 38 | boolChangeBreak(BreakTypebreakType) 39 | { 40 | if(breakType) 41 | { 42 | returntrue; 43 | } 44 | 45 | returnfalse; 46 | } 47 | }; 48 | } 49 | 50 | #endif/*__TRANSPORT_MOUNTAIN_BIKE_H__*/ 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /example/xml/transport_8h.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | transport.h 5 | transport/bicycle.h 6 | transport/racingbike.h 7 | transport/mountainbike.h 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | PEDAL_POWER_MODIFIER 32 | 9000 33 | 34 | 35 | 36 | The modifier value if pedal power is used.This definition exists in the default namespace and is ungrouped. It will not be displayed if the groups options is used. 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | TransportType 46 | 47 | Bycicle 48 | 49 | 50 | 51 | Bycicle type 52 | 53 | 54 | RacingBike 55 | 56 | 57 | 58 | Racing bike type 59 | 60 | 61 | RacingBike 62 | 63 | 64 | 65 | Mountain bike type 66 | 67 | 68 | 69 | 70 | Enum class for transport types.This definition exists in the default namespace and is ungrouped. It will not be displayed if the groups options is used. 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | #ifndef__TRANSPORT_H__ 82 | #define__TRANSPORT_H__ 83 | 84 | #include<transport/bicycle.h> 85 | 86 | #include<transport/racingbike.h> 87 | 88 | #include<transport/mountainbike.h> 89 | 90 | enumclassTransportType{ 91 | Bycicle, 92 | RacingBike, 93 | RacingBike 94 | }; 95 | 96 | #definePEDAL_POWER_MODIFIER9000 97 | 98 | #endif/*__TRANSPORT_H__*/ 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /src/parser.js: -------------------------------------------------------------------------------- 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 log = require('./logger').getLogger(); 11 | var path = require('path'); 12 | var xml2js = require('xml2js'); 13 | 14 | var Compound = require('./compound'); 15 | var helpers = require('./helpers'); 16 | var markdown = require('./markdown'); 17 | 18 | function toMarkdown(element, context) { 19 | var s = ''; 20 | context = context || []; 21 | switch (typeof element) { 22 | case 'string': 23 | s = element; 24 | break; 25 | 26 | case 'object': 27 | if (Array.isArray(element)) { 28 | element.forEach(function (value, key) { 29 | s += toMarkdown(value, context); 30 | }); 31 | } 32 | else { 33 | 34 | // opening the element 35 | switch (element['#name']) { 36 | case 'ref': return s + markdown.refLink(toMarkdown(element.$$), element.$.refid); 37 | case '__text__': s = element._; break; 38 | case 'emphasis': s = '*'; break; 39 | case 'bold': s = '**'; break; 40 | case 'parametername': 41 | case 'computeroutput': s = '`'; break; 42 | case 'parameterlist': 43 | if (element.$.kind == 'exception') { 44 | s = '\n#### Exceptions\n' 45 | } 46 | else { 47 | s = '\n#### Parameters\n' 48 | } 49 | break; 50 | 51 | case 'parameteritem': s = '* '; break; 52 | case 'programlisting': s = '\n```cpp\n'; break; 53 | case 'orderedlist': 54 | context.push(element); 55 | s = '\n\n'; 56 | break; 57 | case 'itemizedlist': s = '\n\n'; break; 58 | case 'listitem': 59 | s = (context.length > 0 && context[context.length - 1]['#name'] == 'orderedlist') ? '1. ' : '* '; 60 | break; 61 | case 'sp': s = ' '; break; 62 | case 'heading': s = '## '; break; 63 | case 'xrefsect': s += '\n> '; break; 64 | case 'simplesect': 65 | if (element.$.kind == 'attention') { 66 | s = '> '; 67 | } 68 | else if (element.$.kind == 'return') { 69 | s = '\n#### Returns\n' 70 | } 71 | else if (element.$.kind == 'see') { 72 | s = '**See also**: ' 73 | } 74 | else { 75 | console.assert(element.$.kind + ' not supported.'); 76 | } 77 | break; 78 | case 'formula': 79 | s = trim(element._); 80 | if (s.startsWith('$') && s.endsWith('$')) return s; 81 | if (s.startsWith('\\[') && s.endsWith('\\]')) 82 | s = trim(s.substring(2, s.length - 2)); 83 | return '\n$$\n' + s + '\n$$\n'; 84 | case 'preformatted': s = '\n
'; break;
 85 | 
 86 |           case 'sect1':
 87 |           case 'sect2':
 88 |           case 'sect3':
 89 |             context.push(element);
 90 |             s = '\n' + helpers.getAnchor(element.$.id, module.exports.parserOptions) + '\n';
 91 |             break;
 92 |           case 'title':
 93 |             var level = '#'.repeat(context[context.length - 1]['#name'].slice(-1));
 94 |             s = '\n#' + level + ' ' + element._ + '\n';
 95 |             break;
 96 | 
 97 |           case 'mdash': s = '—'; break;
 98 |           case 'ndash': s = '–'; break;
 99 |           case 'linebreak': s = '
'; break; 100 | 101 | case 'xreftitle': 102 | case 'entry': 103 | case 'row': 104 | case 'ulink': 105 | case 'codeline': 106 | case 'highlight': 107 | case 'table': 108 | case 'para': 109 | case 'parameterdescription': 110 | case 'parameternamelist': 111 | case 'xrefdescription': 112 | case 'verbatim': 113 | case 'hruler': 114 | case undefined: 115 | break; 116 | 117 | default: 118 | console.error(false, element['#name'] + ': not yet supported.'); 119 | } 120 | 121 | // recurse on children elements 122 | if (element.$$) { 123 | s += toMarkdown(element.$$, context); 124 | } 125 | 126 | // closing the element 127 | switch (element['#name']) { 128 | case 'parameterlist': 129 | case 'para': s += '\n\n'; break; 130 | case 'emphasis': s += '*'; break; 131 | case 'bold': s += '**'; break; 132 | case 'parameteritem': s += '\n'; break; 133 | case "computeroutput": s += '`'; break; 134 | case 'parametername': s += '` '; break; 135 | case 'entry': s = markdown.escape.cell(s) + '|'; break; 136 | case 'programlisting': s += '```\n'; break; 137 | case 'codeline': s += '\n'; break; 138 | case 'ulink': s = markdown.link(s, element.$.url); break; 139 | case 'orderedlist': 140 | context.pop(); 141 | s += '\n'; 142 | break; 143 | case 'itemizedlist': s += '\n'; break; 144 | case 'listitem': s += '\n'; break; 145 | case 'entry': s = ' | '; break; 146 | case 'xreftitle': s += ': '; break; 147 | case 'preformatted': s += '
\n'; break; 148 | case 'sect1': 149 | case 'sect2': 150 | case 'sect3': 151 | context.pop(); 152 | s += '\n'; 153 | break; 154 | case 'row': 155 | s = '\n' + markdown.escape.row(s); 156 | if (element.$$ && element.$$[0].$.thead == "yes") { 157 | element.$$.forEach(function (th, i) { 158 | s += (i ? ' | ' : '\n') + '---------'; 159 | }); 160 | } 161 | break; 162 | } 163 | 164 | } 165 | break; 166 | 167 | default: 168 | console.assert(false); 169 | } 170 | 171 | return s; 172 | } 173 | 174 | function trim(text) { 175 | return text.replace(/^[\s\t\r\n]+|[\s\t\r\n]+$/g, ''); 176 | } 177 | 178 | function copy(dest, property, def) { 179 | dest[property] = trim(toMarkdown(def[property])); 180 | } 181 | 182 | function summary(dest, def) { 183 | // set from briefdescription or first paragraph of detaileddescription 184 | var summary = trim(toMarkdown(def['briefdescription'])); 185 | if (!summary) { 186 | summary = trim(toMarkdown(def['detaileddescription'])); 187 | if (summary) { 188 | var firstSentence = summary.split('\n', 1)[0]; //.split('. ').first; 189 | if (firstSentence) 190 | summary = firstSentence; 191 | } 192 | } 193 | dest['summary'] = summary; 194 | } 195 | 196 | module.exports = { 197 | 198 | // All references indexed by refid 199 | references: {}, 200 | 201 | // The root compound 202 | root: new Compound(), 203 | 204 | parseMembers: function (compound, props, membersdef) { 205 | 206 | // copy all properties 207 | Object.keys(props).forEach(function(prop) { 208 | compound[prop] = props[prop]; 209 | }); 210 | 211 | this.references[compound.refid] = compound; 212 | 213 | if (membersdef) { 214 | membersdef.forEach(function (memberdef) { 215 | var member = { name: memberdef.name[0], parent: compound }; 216 | compound.members.push(member); 217 | Object.keys(memberdef.$).forEach(function(prop) { 218 | member[prop] = memberdef.$[prop]; 219 | }); 220 | this.references[member.refid] = member; 221 | }.bind(this)); 222 | } 223 | }, 224 | 225 | parseMember: function (member, section, memberdef) { 226 | log.verbose('Processing member ' + member.kind + ' ' + member.name); 227 | member.section = section; 228 | copy(member, 'briefdescription', memberdef); 229 | copy(member, 'detaileddescription', memberdef); 230 | summary(member, memberdef); 231 | 232 | var m = []; 233 | switch (member.kind) { 234 | case 'signal': 235 | case 'slot': 236 | m = m.concat(['{', member.kind, '} ']); 237 | 238 | case 'function': 239 | m = m.concat(memberdef.$.prot, ' '); // public, private, ... 240 | if (memberdef.templateparamlist) { 241 | m.push('template<'); 242 | if (memberdef.templateparamlist.length > 0 && memberdef.templateparamlist.param) { 243 | memberdef.templateparamlist[0].param.forEach(function (param, argn) { 244 | m = m.concat(argn == 0 ? [] : ','); 245 | m = m.concat([toMarkdown(param.type)]); 246 | m = m.concat(param.declname ? [' ', toMarkdown(param.declname)] : []); 247 | }); 248 | } 249 | m.push('> \n'); 250 | } 251 | m = m.concat(memberdef.$.inline == 'yes' ? ['inline', ' '] : []); 252 | m = m.concat(memberdef.$.static == 'yes' ? ['static', ' '] : []); 253 | m = m.concat(memberdef.$.virt == 'virtual' ? ['virtual', ' '] : []); 254 | m = m.concat(toMarkdown(memberdef.type), ' '); 255 | m = m.concat(memberdef.$.explicit == 'yes' ? ['explicit', ' '] : []); 256 | // m = m.concat(memberdef.name[0]._); 257 | m = m.concat(markdown.refLink(member.name, member.refid)); 258 | m = m.concat('('); 259 | if (memberdef.param) { 260 | memberdef.param.forEach(function (param, argn) { 261 | m = m.concat(argn == 0 ? [] : ', '); 262 | m = m.concat([toMarkdown(param.type)]); 263 | m = m.concat(param.declname ? [' ', toMarkdown(param.declname)] : []); 264 | }); 265 | } 266 | 267 | m = m.concat(')'); 268 | m = m.concat(memberdef.$['const'] == 'yes' ? [' ', 'const'] : []); 269 | m = m.concat(memberdef.argsstring[0]._.match(/noexcept$/) ? ' noexcept' : ''); 270 | m = m.concat(memberdef.argsstring[0]._.match(/=\s*delete$/) ? ' = delete' : ''); 271 | m = m.concat(memberdef.argsstring[0]._.match(/=\s*default/) ? ' = default' : ''); 272 | break; 273 | 274 | case 'variable': 275 | m = m.concat(memberdef.$.prot, ' '); // public, private, ... 276 | m = m.concat(memberdef.$.static == 'yes' ? ['static', ' '] : []); 277 | m = m.concat(memberdef.$.mutable == 'yes' ? ['mutable', ' '] : []); 278 | m = m.concat(toMarkdown(memberdef.type), ' '); 279 | // m = m.concat(memberdef.name[0]._); 280 | m = m.concat(markdown.refLink(member.name, member.refid)); 281 | break; 282 | 283 | case 'property': 284 | m = m.concat(['{', member.kind, '} ']); 285 | m = m.concat(toMarkdown(memberdef.type), ' '); 286 | // m = m.concat(memberdef.name[0]._); 287 | m = m.concat(markdown.refLink(member.name, member.refid)); 288 | break; 289 | 290 | case 'enum': 291 | member.enumvalue = []; 292 | if (memberdef.enumvalue) { 293 | memberdef.enumvalue.forEach(function (param, argn) { 294 | var enumvalue = {} 295 | copy(enumvalue, 'name', param); 296 | copy(enumvalue, 'briefdescription', param); 297 | copy(enumvalue, 'detaileddescription', param); 298 | summary(enumvalue, param); 299 | member.enumvalue.push(enumvalue); 300 | }); 301 | } 302 | // m.push(member.kind + ' ' + member.name); 303 | m = m.concat([member.kind, ' ', markdown.refLink(member.name, member.refid)]); 304 | break; 305 | 306 | default: 307 | // m.push(member.kind + ' ' + member.name); 308 | m = m.concat([member.kind, ' ', markdown.refLink(member.name, member.refid)]); 309 | break; 310 | } 311 | 312 | member.proto = helpers.inline(m); 313 | }, 314 | 315 | assignToNamespace: function (compound, child) { 316 | if (compound.name != child.namespace) 317 | console.assert('namespace mismatch: ', compound.name, '!=', child.namespace); 318 | 319 | // namespaces take ownership of the child compound 320 | if (child.parent) 321 | delete child.parent.compounds[child.id]; 322 | compound.compounds[child.id] = child; 323 | child.parent = compound; 324 | }, 325 | 326 | assignNamespaceToGroup: function (compound, child) { 327 | 328 | // add the namespace to the group 329 | compound.compounds[child.id] = child; 330 | 331 | // remove namespace clildren from direct group children 332 | Object.keys(child.compounds).forEach(function(id) { 333 | delete compound.compounds[id]; 334 | }); 335 | }, 336 | 337 | assignClassToGroup: function (compound, child) { 338 | 339 | // add the namespace to the group 340 | // if the child already belongs to a child namespace it will be removed 341 | // on the call to `assignNamespaceToGroup` 342 | compound.compounds[child.id] = child; 343 | 344 | // add a groupid and reference to the compound and all it's members 345 | child.groupid = compound.id; 346 | child.groupname = compound.name; 347 | 348 | child.members.forEach(function (member) { 349 | member.groupid = compound.id; 350 | member.groupname = compound.name; 351 | }); 352 | }, 353 | 354 | extractPageSections: function(page, elements) { 355 | elements.forEach(function(element) { 356 | if (element['#name'] == 'sect1' || element['#name'] == 'sect2' || element['#name'] == 'sect3') { 357 | var id = element.$.id; 358 | var member = { section: element['#name'], id: id, name: id, refid: id, parent: page }; 359 | page.members.push(member); 360 | this.references[member.refid] = member; 361 | } 362 | if (element.$$) 363 | this.extractPageSections(page, element.$$); 364 | }.bind(this)); 365 | }, 366 | 367 | parseCompound: function (compound, compounddef) { 368 | log.verbose('Processing compound ' + compound.name); 369 | Object.keys(compounddef.$).forEach(function(prop) { 370 | compound[prop] = compounddef.$[prop]; 371 | }); 372 | compound.fullname = compounddef.compoundname[0]._; 373 | copy(compound, 'briefdescription', compounddef); 374 | copy(compound, 'detaileddescription', compounddef); 375 | summary(compound, compounddef); 376 | 377 | if (compounddef.basecompoundref) { 378 | compounddef.basecompoundref.forEach(function (basecompoundref) { 379 | compound.basecompoundref.push({ 380 | prot: basecompoundref.$.prot, 381 | name: basecompoundref._, 382 | }); 383 | }); 384 | } 385 | 386 | if (compounddef.sectiondef) { 387 | compounddef.sectiondef.forEach(function (section) { 388 | // switch (section.$['kind']) { 389 | // case 'define': 390 | // case 'enum': 391 | // case 'friend': 392 | // case 'public-attrib': 393 | // case 'public-func': 394 | // case 'protected-attrib': 395 | // case 'protected-func': 396 | // case 'private-attrib': 397 | // case 'private-func': 398 | if (section.memberdef) { 399 | section.memberdef.forEach(function (memberdef) { 400 | var member = this.references[memberdef.$.id]; 401 | 402 | if (compound.kind == 'group') { 403 | member.groupid = compound.id; 404 | member.groupname = compound.name; 405 | } 406 | else if (compound.kind == 'file') { 407 | // add free members defined inside files in the default 408 | // namespace to the root compound 409 | this.root.members.push(member); 410 | } 411 | this.parseMember(member, section.$['kind'], memberdef); 412 | }.bind(this)); 413 | } 414 | // break; 415 | // 416 | // default: 417 | // console.assert(true); 418 | // } 419 | }.bind(this)); 420 | } 421 | 422 | compound.proto = helpers.inline([compound.kind, ' ', markdown.refLink(compound.name, compound.refid)]); 423 | 424 | // kind specific parsing 425 | switch (compound.kind) { 426 | case 'class': 427 | case 'struct': 428 | case 'union': 429 | case 'typedef': 430 | 431 | // set namespace reference 432 | var nsp = compound.name.split('::'); 433 | compound.namespace = nsp.splice(0, nsp.length - 1).join('::'); 434 | break; 435 | 436 | case 'file': 437 | // NOTE: to handle free functions in the default namespace we would 438 | // parse add all contained members to the root compound. 439 | break; 440 | 441 | case 'page': 442 | this.extractPageSections(compound, compounddef.$$); 443 | break; 444 | 445 | case 'namespace': 446 | case 'group': 447 | 448 | if (compound.kind == 'group') { 449 | compound.groupid = compound.id; 450 | compound.groupname = compound.name; 451 | } 452 | 453 | // handle innerclass for groups and namespaces 454 | if (compounddef.innerclass) { 455 | compounddef.innerclass.forEach(function (innerclassdef) { 456 | if (compound.kind == 'namespace') { 457 | // log.verbose('Assign ' + innerclassdef.$.refid + ' to namespace ' + compound.name); 458 | 459 | if (this.references[innerclassdef.$.refid]) 460 | this.assignToNamespace(compound, this.references[innerclassdef.$.refid]); 461 | } 462 | else if (compound.kind == 'group') { 463 | // log.verbose('Assign ' + innerclassdef.$.refid + ' to group ' + compound.name); 464 | if (this.references[innerclassdef.$.refid]) 465 | this.assignClassToGroup(compound, this.references[innerclassdef.$.refid]); 466 | } 467 | }.bind(this)); 468 | } 469 | 470 | // handle innernamespace for groups and namespaces 471 | if (compounddef.innernamespace) { 472 | compound.innernamespaces = []; 473 | compounddef.innernamespace.forEach(function (namespacedef) { 474 | if (compound.kind == 'group') { 475 | // log.verbose('Assign namespace ' + namespacedef.$.refid + ' to group ' + compound.name); 476 | this.assignNamespaceToGroup(compound, this.references[namespacedef.$.refid]); 477 | } 478 | }.bind(this)); 479 | } 480 | break; 481 | default: 482 | console.assert(true); 483 | } 484 | 485 | return; 486 | }, 487 | 488 | parseIndex: function (root, index, options) { 489 | index.forEach(function (element) { 490 | var doxygen, compound = root.find(element.$.refid, element.name[0], true); 491 | var xmlParser = new xml2js.Parser({ 492 | explicitChildren: true, 493 | preserveChildrenOrder: true, 494 | charsAsChildren: true 495 | }); 496 | 497 | this.parseMembers(compound, element.$, element.member); 498 | 499 | if (compound.kind !== 'file') { // && compound.kind !== 'file' 500 | log.verbose('Parsing ' + path.join(options.directory, compound.refid + '.xml')); 501 | doxygen = fs.readFileSync(path.join(options.directory, compound.refid + '.xml'), 'utf8'); 502 | xmlParser.parseString(doxygen, function (err, data) { 503 | if (err) { 504 | log.verbose('warning - parse error for file: ' + path.join(options.directory, compound.refid + '.xml')) 505 | return; 506 | } 507 | this.parseCompound(compound, data.doxygen.compounddef[0]); 508 | }.bind(this)); 509 | } 510 | 511 | }.bind(this)); 512 | }, 513 | 514 | loadIndex: function (options, callback) { 515 | this.parserOptions = options; 516 | log.verbose('Parsing ' + path.join(options.directory, 'index.xml')); 517 | fs.readFile(path.join(options.directory, 'index.xml'), 'utf8', function(err, data) { 518 | if (err) { 519 | callback('Failed to load doxygen XML: ' + err); 520 | return; 521 | } 522 | var xmlParser = new xml2js.Parser(); 523 | xmlParser.parseString(data, function (err, result) { 524 | if (err) { 525 | callback('Failed to parse doxygen XML: ' + err); 526 | return; 527 | } 528 | this.root.kind = 'index'; 529 | this.parseIndex(this.root, result.doxygenindex.compound, options); 530 | callback(null, this.root); // TODO: return errors properly 531 | }.bind(this)); 532 | }.bind(this)); 533 | }, 534 | }; 535 | -------------------------------------------------------------------------------- /example/xml/compound.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | 808 | 809 | 810 | 811 | 812 | 813 | 814 | 815 | 816 | 817 | 818 | 819 | 820 | 821 | 822 | 823 | 824 | 825 | 826 | 827 | 828 | 829 | 830 | 831 | 832 | 833 | 834 | 835 | 836 | 837 | 838 | 839 | 840 | 841 | 842 | 843 | 844 | 845 | 846 | 847 | 848 | 849 | 850 | 851 | 852 | 853 | 854 | 855 | 856 | 857 | 858 | 859 | 860 | 861 | 862 | 863 | 864 | 865 | 866 | 867 | 868 | 869 | 870 | 871 | 872 | 873 | 874 | 875 | 876 | 877 | 878 | 879 | 880 | 881 | 882 | 883 | 884 | 885 | 886 | 887 | 888 | 889 | 890 | 891 | 892 | 893 | 894 | 895 | 896 | 897 | 898 | 899 | 900 | 901 | 902 | 903 | 904 | 905 | 906 | 907 | 908 | 909 | 910 | 911 | 912 | 913 | 914 | 915 | 916 | 917 | 918 | 919 | 920 | 921 | 922 | 923 | 924 | 925 | 926 | 927 | 928 | 929 | 930 | 931 | 932 | 933 | 934 | 935 | 936 | 937 | 938 | 939 | 940 | 941 | 942 | 943 | 944 | 945 | 946 | 947 | 948 | 949 | 950 | 951 | 952 | 953 | 954 | 955 | 956 | 957 | 958 | 959 | 960 | 961 | 962 | 963 | 964 | 965 | 966 | 967 | 968 | 969 | 970 | 971 | 972 | 973 | 974 | 975 | 976 | 977 | 978 | 979 | 980 | 981 | 982 | 983 | 984 | 985 | 986 | 987 | 988 | 989 | 990 | 991 | 992 | 993 | 994 | 995 | 996 | 997 | 998 | 999 | 1000 | 1001 | 1002 | 1003 | 1004 | 1005 | 1006 | 1007 | 1008 | 1009 | 1010 | 1011 | 1012 | 1013 | 1014 | 1015 | 1016 | 1017 | 1018 | 1019 | 1020 | 1021 | 1022 | 1023 | 1024 | 1025 | 1026 | 1027 | 1028 | 1029 | 1030 | 1031 | 1032 | 1033 | 1034 | 1035 | 1036 | 1037 | 1038 | 1039 | 1040 | 1041 | 1042 | 1043 | 1044 | 1045 | 1046 | 1047 | 1048 | 1049 | 1050 | 1051 | 1052 | 1053 | 1054 | 1055 | 1056 | 1057 | 1058 | 1059 | 1060 | 1061 | 1062 | 1063 | 1064 | 1065 | 1066 | 1067 | 1068 | 1069 | 1070 | 1071 | 1072 | 1073 | 1074 | 1075 | 1076 | 1077 | 1078 | 1079 | 1080 | 1081 | 1082 | 1083 | 1084 | 1085 | 1086 | 1087 | 1088 | 1089 | 1090 | 1091 | 1092 | 1093 | 1094 | 1095 | 1096 | 1097 | 1098 | 1099 | 1100 | 1101 | 1102 | 1103 | 1104 | 1105 | 1106 | 1107 | 1108 | 1109 | 1110 | 1111 | 1112 | 1113 | 1114 | 1115 | 1116 | 1117 | 1118 | 1119 | 1120 | 1121 | 1122 | 1123 | 1124 | 1125 | 1126 | 1127 | 1128 | 1129 | 1130 | 1131 | 1132 | --------------------------------------------------------------------------------