mirror of
https://github.com/eclipse/upm.git
synced 2025-03-15 04:57:30 +03:00
jsdoc: scripts for generating node.js documentation
Signed-off-by: Mihai Tudor Panu <mihai.tudor.panu@intel.com>
This commit is contained in:
parent
1079cb7cdd
commit
65a19d1779
60
doxy/node/docgen.js
Normal file
60
doxy/node/docgen.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Author: Heidi Pan <heidi.pan@intel.com>
|
||||||
|
* Copyright (c) 2015 Intel Corporation.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// dependencies
|
||||||
|
var xml2js = require('./xml2js')
|
||||||
|
, fs = require('fs')
|
||||||
|
, Promise = require('bluebird')
|
||||||
|
, opts = require('commander')
|
||||||
|
, _ = require('lodash')
|
||||||
|
, mkdirp = require('mkdirp');
|
||||||
|
|
||||||
|
|
||||||
|
// parse command line arguments
|
||||||
|
_.extend(opts, { addOptions: function(module) { return module.addOptions(opts); } });
|
||||||
|
opts
|
||||||
|
.option('-m, --module [module]', 'module name for which to build documentation', 'mraa')
|
||||||
|
.option('-f, --formats [formats]', 'format for js comments', 'jsdoc,yuidoc,ternjs')
|
||||||
|
.option('-o, --outdir [directory]', 'top directory to build documentation', __dirname + '/jsdoc')
|
||||||
|
.addOptions(xml2js)
|
||||||
|
.parse(process.argv);
|
||||||
|
|
||||||
|
|
||||||
|
// use promise-style programming rather than spaghetti callbacks
|
||||||
|
Promise.promisifyAll(fs);
|
||||||
|
|
||||||
|
// TODO: create directory structure if doesn't exist
|
||||||
|
var formats = opts.formats.split(',');
|
||||||
|
formats.forEach(function(format){
|
||||||
|
mkdirp('jsdoc/' + format + '/' + opts.module);
|
||||||
|
});
|
||||||
|
|
||||||
|
// main
|
||||||
|
xml2js.parse().then(function(specjs) {
|
||||||
|
Promise.all(_.map(formats, function(format) {
|
||||||
|
var generateDocs = require(__dirname + '/generators/' + format + '/generator');
|
||||||
|
var outFile = opts.outdir + '/' + format + '/' + specjs.MODULE + '/doc.js';
|
||||||
|
return fs.writeFileAsync(outFile, generateDocs(specjs));
|
||||||
|
}));
|
||||||
|
});
|
7
doxy/node/generators/jsdoc/conf.json
Normal file
7
doxy/node/generators/jsdoc/conf.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"templates": {
|
||||||
|
"default": {
|
||||||
|
"outputSourceFiles": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
88
doxy/node/generators/jsdoc/generator.js
Normal file
88
doxy/node/generators/jsdoc/generator.js
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Author: Heidi Pan <heidi.pan@intel.com>
|
||||||
|
* Copyright (c) 2015 Intel Corporation.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// dependencies
|
||||||
|
var _ = require('lodash');
|
||||||
|
|
||||||
|
|
||||||
|
// generate JSDoc-style documentation
|
||||||
|
function generateDocs(specjs) {
|
||||||
|
var docs = GENERATE_MODULE(specjs.MODULE);
|
||||||
|
docs = _.reduce(specjs.METHODS, function(memo, methodSpec, methodName) {
|
||||||
|
return memo += GENERATE_METHOD(methodName, methodSpec);
|
||||||
|
}, docs);
|
||||||
|
docs = _.reduce(specjs.ENUMS, function(memo, enumSpec, enumName) {
|
||||||
|
return memo += GENERATE_ENUM(enumName, enumSpec);
|
||||||
|
}, docs);
|
||||||
|
docs = _.reduce(specjs.CLASSES, function(memo, classSpec, parentClass) {
|
||||||
|
return _.reduce(classSpec.methods, function(memo, methodSpec, methodName) {
|
||||||
|
return memo += GENERATE_METHOD(methodName, methodSpec, parentClass);
|
||||||
|
}, memo);
|
||||||
|
}, docs);
|
||||||
|
return docs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// comment wrapper around entire spec
|
||||||
|
function GENERATE_DOC(text) {
|
||||||
|
return '/**\n' + text + ' */\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// generate module spec
|
||||||
|
function GENERATE_MODULE(module) {
|
||||||
|
return GENERATE_DOC('@module ' + module + '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// generate method spec with parent module/class
|
||||||
|
function GENERATE_METHOD(name, spec, parent) {
|
||||||
|
return GENERATE_DOC(spec.description + '\n'
|
||||||
|
+ '@method ' + name + '\n'
|
||||||
|
+ '@instance\n'
|
||||||
|
+ (parent ? ('@memberof ' + parent + '\n') : '')
|
||||||
|
+ _.reduce(spec.params, function(memo, paramSpec, paramName) {
|
||||||
|
return '@param {' + paramSpec.type + '} ' + paramName + ' ' + paramSpec.description + '\n';
|
||||||
|
}, '')
|
||||||
|
+ ( !_.isEmpty(spec.return) ? ('@return {' + spec.return.type + '} ' + spec.return.description + '\n') : ''));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// generate enum spec
|
||||||
|
function GENERATE_ENUM(name, spec) {
|
||||||
|
return GENERATE_DOC(spec.description + '\n\n'
|
||||||
|
+ '@var ' + name + '\n'
|
||||||
|
+ '@type Enum(' + spec.type + ')\n'
|
||||||
|
+ '@instance\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// generate link spec
|
||||||
|
function GENERATE_LINK(text) {
|
||||||
|
return '{@link ' + text + '}';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = generateDocs;
|
110
doxy/node/generators/ternjs/generator.js
Normal file
110
doxy/node/generators/ternjs/generator.js
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* Author: Heidi Pan <heidi.pan@intel.com>
|
||||||
|
* Copyright (c) 2015 Intel Corporation.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// dependencies
|
||||||
|
var _ = require('lodash');
|
||||||
|
|
||||||
|
|
||||||
|
// generate json for ternjs input
|
||||||
|
function generateDocs(specjs) {
|
||||||
|
var docs = GENERATE_MODULE(specjs.MODULE);
|
||||||
|
GENERATE_TYPE = (function(enums) {
|
||||||
|
return function(type) {
|
||||||
|
return (_.contains(enums, type) ? ('Enum ' + type) : type);
|
||||||
|
}
|
||||||
|
})(_.keys(specjs.ENUMS_BY_GROUP));
|
||||||
|
_.each(specjs.ENUMS, function(enumSpec, enumName) {
|
||||||
|
_.extend(docs[specjs.MODULE], GENERATE_ENUM(enumName, enumSpec));
|
||||||
|
});
|
||||||
|
_.each(specjs.METHODS, function(methodSpec, methodName) {
|
||||||
|
_.extend(docs[specjs.MODULE], GENERATE_METHOD(methodName, methodSpec));
|
||||||
|
});
|
||||||
|
_.each(specjs.CLASSES, function(classSpec, parentClass) {
|
||||||
|
var constructor = classSpec.methods[parentClass];
|
||||||
|
_.extend(docs[specjs.MODULE], GENERATE_METHOD(parentClass, constructor ? constructor : { params: {}, return: {}, description: '' } ));
|
||||||
|
_.each(classSpec.enums, function(enumSpec, enumName) {
|
||||||
|
_.extend(docs[specjs.MODULE][parentClass], GENERATE_ENUM(enumName, enumSpec));
|
||||||
|
});
|
||||||
|
docs[specjs.MODULE][parentClass].prototype = {};
|
||||||
|
_.each(_.omit(classSpec.methods, parentClass), function(methodSpec, methodName) {
|
||||||
|
_.extend(docs[specjs.MODULE][parentClass].prototype, GENERATE_METHOD(methodName, methodSpec));
|
||||||
|
});
|
||||||
|
_.each(classSpec.variables, function(variableSpec, variableName) {
|
||||||
|
_.extend(docs[specjs.MODULE][parentClass].prototype, GENERATE_VARIABLE(variableName, variableSpec));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return JSON.stringify(docs, null, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// generate module spec
|
||||||
|
function GENERATE_MODULE(module) {
|
||||||
|
var docs = { '!name': module + 'library' };
|
||||||
|
docs[module] = {};
|
||||||
|
return docs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// generate method spec
|
||||||
|
function GENERATE_METHOD(name, spec) {
|
||||||
|
var doc = {};
|
||||||
|
doc[name] = {
|
||||||
|
'!type': 'fn(' + GENERATE_PARAMS(spec.params) + ')' + GENERATE_RETURN(spec.return),
|
||||||
|
'!doc': spec.description
|
||||||
|
}
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// generate parameter signatures for method
|
||||||
|
function GENERATE_PARAMS(spec) {
|
||||||
|
return _.map(spec, function(paramSpec, paramName) {
|
||||||
|
return paramName + ': ' + paramSpec.type;
|
||||||
|
}).join(', ');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// generate return signature for method
|
||||||
|
function GENERATE_RETURN(spec) {
|
||||||
|
return (_.isEmpty(spec) ? '' : (' -> ' + spec.type));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// generate enum spec
|
||||||
|
function GENERATE_ENUM(name, spec) {
|
||||||
|
var doc = {};
|
||||||
|
doc[name] = 'Enum ' + spec.type ;
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// generate variable spec
|
||||||
|
function GENERATE_VARIABLE(name, spec) {
|
||||||
|
var doc = {};
|
||||||
|
doc[name]= spec.type ;
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = generateDocs;
|
8
doxy/node/generators/yuidoc/conf.json
Normal file
8
doxy/node/generators/yuidoc/conf.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"name": "UPM",
|
||||||
|
"description": "The UPM API: High Level Sensor Library for Intel IoT Devices Using MRAA",
|
||||||
|
"logo": "http://upload.wikimedia.org/wikipedia/commons/8/8c/Transparent.png",
|
||||||
|
"options": {
|
||||||
|
"outdir": "./html/node"
|
||||||
|
}
|
||||||
|
}
|
117
doxy/node/generators/yuidoc/generator.js
vendored
Normal file
117
doxy/node/generators/yuidoc/generator.js
vendored
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* Author: Heidi Pan <heidi.pan@intel.com>
|
||||||
|
* Copyright (c) 2015 Intel Corporation.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// dependencies
|
||||||
|
var _ = require('lodash');
|
||||||
|
|
||||||
|
|
||||||
|
// generate YuiDocs-style documentation
|
||||||
|
function generateDocs(specjs) {
|
||||||
|
var docs = GENERATE_MODULE(specjs.MODULE);
|
||||||
|
GENERATE_TYPE = (function(enums) {
|
||||||
|
return function(type) {
|
||||||
|
return (_.contains(enums, type) ? ('Enum ' + type) : type);
|
||||||
|
}
|
||||||
|
})(_.keys(specjs.ENUMS_BY_GROUP));
|
||||||
|
docs = _.reduce(specjs.METHODS, function(memo, methodSpec, methodName) {
|
||||||
|
return memo += GENERATE_METHOD(methodName, methodSpec);
|
||||||
|
}, docs);
|
||||||
|
docs = _.reduce(specjs.ENUMS, function(memo, enumSpec, enumName) {
|
||||||
|
return memo += GENERATE_ENUM(enumName, enumSpec);
|
||||||
|
}, docs);
|
||||||
|
docs = _.reduce(specjs.CLASSES, function(memo, classSpec, parentClass) {
|
||||||
|
return memo
|
||||||
|
+ GENERATE_CLASS(parentClass, classSpec.description)
|
||||||
|
+ _.reduce(classSpec.methods, function(memo, methodSpec, methodName) {
|
||||||
|
return memo += GENERATE_METHOD(methodName, methodSpec, parentClass);
|
||||||
|
}, '')
|
||||||
|
+ _.reduce(classSpec.variables, function(memo, variableSpec, variableName) {
|
||||||
|
return memo += GENERATE_VAR(variableName, variableSpec, parentClass);
|
||||||
|
}, '')
|
||||||
|
+ _.reduce(classSpec.enums, function(memo, enumSpec, enumName) {
|
||||||
|
return memo += GENERATE_ENUM(enumName, enumSpec, parentClass);
|
||||||
|
}, '');
|
||||||
|
}, docs);
|
||||||
|
return docs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// comment wrapper around entire spec
|
||||||
|
function GENERATE_DOC(text) {
|
||||||
|
return '/**\n' + text + ' */\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// generate module spec
|
||||||
|
function GENERATE_MODULE(module) {
|
||||||
|
return GENERATE_DOC('@module ' + module + '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// generate class spec
|
||||||
|
function GENERATE_CLASS(name, description) {
|
||||||
|
return GENERATE_DOC(description + '\n'
|
||||||
|
+ '@class ' + name + '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// generate method spec with parent module/class
|
||||||
|
function GENERATE_METHOD(name, spec, parent) {
|
||||||
|
return GENERATE_DOC(spec.description + '\n'
|
||||||
|
+ '@method ' + name + '\n'
|
||||||
|
+ (parent ? ('@for ' + parent + '\n') : '@for common\n')
|
||||||
|
+ _.reduce(spec.params, function(memo, paramSpec, paramName) {
|
||||||
|
return memo + '@param {' + GENERATE_TYPE(paramSpec.type) + '} ' + paramName + ' ' + paramSpec.description + '\n';
|
||||||
|
}, '')
|
||||||
|
+ ( !_.isEmpty(spec.return) ? ('@return {' + GENERATE_TYPE(spec.return.type) + '} ' + spec.return.description + '\n') : ''));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// generate enum spec
|
||||||
|
function GENERATE_ENUM(name, spec, parent) {
|
||||||
|
return GENERATE_DOC(spec.description + '\n'
|
||||||
|
+ '@property ' + name + '\n'
|
||||||
|
+ '@type Enum ' + spec.type + '\n'
|
||||||
|
+ '@for ' + (parent ? parent : 'common') + '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// generate variable specs
|
||||||
|
function GENERATE_VAR(name, spec, parent) {
|
||||||
|
return GENERATE_DOC(spec.description + '\n'
|
||||||
|
+ '@property ' + name + '\n'
|
||||||
|
+ '@type ' + spec.type + '\n'
|
||||||
|
+ '@for ' + parent + '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// generate link spec
|
||||||
|
function GENERATE_LINK(text) {
|
||||||
|
return '{{#crossLink "' + text + '"}}{{/crossLink}}';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = generateDocs;
|
45
doxy/node/grammars/xml.peg
Normal file
45
doxy/node/grammars/xml.peg
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
document
|
||||||
|
= _ ignore* _ "<doxygen " _ attr:attr* _ ">" body:elements _ "</doxygen>" _ { return body; }
|
||||||
|
|
||||||
|
|
||||||
|
elements
|
||||||
|
= element*
|
||||||
|
|
||||||
|
element
|
||||||
|
= _ "<" startTag:id _ attr:attr* _ ">" _ children:elements _ "</" endTag:id ">" _ {
|
||||||
|
if (startTag != endTag) {
|
||||||
|
throw new Error("Expected </" + startTag + "> but </" + endTag + "> found.");
|
||||||
|
}
|
||||||
|
return {name: startTag, attr: attr, children: children }
|
||||||
|
}
|
||||||
|
/ "<" tag:id _ attr:attr* _ "/>" _ {
|
||||||
|
return {name: tag, attr: attr }
|
||||||
|
}
|
||||||
|
/ _ text:text _ { return text }
|
||||||
|
|
||||||
|
ignore
|
||||||
|
= "<?xml" _ attr* _ "?>" { return }
|
||||||
|
|
||||||
|
attr
|
||||||
|
= name:id _ "=" _ value:string { return { name:name, value:value } }
|
||||||
|
|
||||||
|
string
|
||||||
|
= '"' '"' _ { return ""; }
|
||||||
|
/ "'" "'" _ { return ""; }
|
||||||
|
/ '"' text:quoted '"' _ { return text; }
|
||||||
|
/ "'" text:quoted "'" _ { return text; }
|
||||||
|
|
||||||
|
quoted
|
||||||
|
= chars:[^<>'" \t\n\r]+ { return chars.join(""); }
|
||||||
|
|
||||||
|
text
|
||||||
|
= chars:[^<> \t\n\r]+ { return chars.join(""); }
|
||||||
|
|
||||||
|
id
|
||||||
|
= chars:[^<>/'"=? \t\n\r]+ { return chars.join(""); }
|
||||||
|
|
||||||
|
_ "whitespace"
|
||||||
|
= whitespace*
|
||||||
|
|
||||||
|
whitespace
|
||||||
|
= [ \t\n\r]
|
125
doxy/node/tolower.js
Normal file
125
doxy/node/tolower.js
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* Author: Dina M Suehiro <dina.m.suehiro@intel.com>
|
||||||
|
* Copyright (c) 2015 Intel Corporation.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// dependencies
|
||||||
|
var opts = require('commander'), // for command line args
|
||||||
|
fs = require('fs'), // for file system access
|
||||||
|
path = require('path'); // for file path parsing
|
||||||
|
|
||||||
|
// parse command line arguments
|
||||||
|
opts
|
||||||
|
.option('-i, --inputdir [directory]', 'product documents directory', __dirname + '/docs/yuidoc/upm')
|
||||||
|
.parse(process.argv);
|
||||||
|
|
||||||
|
// Set to true for console output
|
||||||
|
var debug = true;
|
||||||
|
|
||||||
|
// Global arrays tracking the files that have been renamed
|
||||||
|
var originalFiles = [];
|
||||||
|
var renamedFiles = [];
|
||||||
|
|
||||||
|
// Filter to get html files from different directories
|
||||||
|
var rootFiles = getHtmlFilenames(opts.inputdir);
|
||||||
|
var classesFiles = getHtmlFilenames(opts.inputdir + "/classes");
|
||||||
|
var modulesFiles = getHtmlFilenames(opts.inputdir + "/modules");
|
||||||
|
|
||||||
|
// Rename files in the classes directory to have lower-cased file names.
|
||||||
|
renameFiles(classesFiles);
|
||||||
|
|
||||||
|
classesFiles = getHtmlFilenames(opts.inputdir + "/classes");
|
||||||
|
|
||||||
|
// Go through the html files and update links to reflect the file names that we changed.
|
||||||
|
renameLinks(rootFiles);
|
||||||
|
renameLinks(classesFiles);
|
||||||
|
renameLinks(modulesFiles);
|
||||||
|
|
||||||
|
// Helper function that returns paths to the html files in the specified directory
|
||||||
|
function getHtmlFilenames (directory)
|
||||||
|
{
|
||||||
|
return fs.readdirSync(directory).map(function (file) {
|
||||||
|
return path.join(directory, file);
|
||||||
|
}).filter(function (file) {
|
||||||
|
return fs.statSync(file).isFile();
|
||||||
|
}).filter(function (file) {
|
||||||
|
return path.extname(file).toLowerCase() == ".html";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Goes through the files and renames them to be lower-cased and tracks them the
|
||||||
|
// renamed files in the originalFiles[] and renamedFiles[] arrays.
|
||||||
|
function renameFiles(files)
|
||||||
|
{
|
||||||
|
files.forEach(function (file)
|
||||||
|
{
|
||||||
|
var originalName = path.basename(file);
|
||||||
|
var newFileName = originalName.toLowerCase();
|
||||||
|
var directory = path.dirname(file);
|
||||||
|
if (originalName != newFileName)
|
||||||
|
{
|
||||||
|
fs.renameSync(file, directory + "/" + newFileName); //, function(err)
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
console.log('Renamed: %s --> %s', originalName, newFileName);
|
||||||
|
|
||||||
|
originalFiles.push(originalName);
|
||||||
|
renamedFiles.push(newFileName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function goes through the specified files and does a file/replace of the
|
||||||
|
// originalFiles to the renamedFiles so that the .html links match what has been renamed.
|
||||||
|
function renameLinks (files)
|
||||||
|
{
|
||||||
|
if (originalFiles.length <= 0)
|
||||||
|
{
|
||||||
|
if (debug)
|
||||||
|
console.log("No links to rename.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
files.forEach(function (file)
|
||||||
|
{
|
||||||
|
// Read the file
|
||||||
|
data = fs.readFileSync(file, 'ascii');
|
||||||
|
|
||||||
|
// Find/replace the file names that were renamed
|
||||||
|
for (var i = 0; i < originalFiles.length; i++)
|
||||||
|
{
|
||||||
|
var findString = '/' + originalFiles[i] + '\"';
|
||||||
|
var replaceString = '/' + renamedFiles[i] + '\"';
|
||||||
|
|
||||||
|
data = data.replace(findString, replaceString);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write back
|
||||||
|
fs.writeFile(file, data, 'ascii', function (err) {
|
||||||
|
if (err)
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
console.log('Renamed links in: %s', file);
|
||||||
|
});
|
||||||
|
}
|
575
doxy/node/xml2js.js
Normal file
575
doxy/node/xml2js.js
Normal file
@ -0,0 +1,575 @@
|
|||||||
|
/*
|
||||||
|
* Author: Heidi Pan <heidi.pan@intel.com>
|
||||||
|
* Copyright (c) 2015 Intel Corporation.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// dependencies
|
||||||
|
var peg = require('pegjs')
|
||||||
|
, fs = require('fs')
|
||||||
|
, path = require('path')
|
||||||
|
, Promise = require('bluebird')
|
||||||
|
, _ = require('lodash')
|
||||||
|
, util = require('util');
|
||||||
|
|
||||||
|
|
||||||
|
// use promise-style programming rather than spaghetti callbacks
|
||||||
|
Promise.promisifyAll(fs);
|
||||||
|
|
||||||
|
|
||||||
|
var xml2js = {
|
||||||
|
|
||||||
|
// js-format specs
|
||||||
|
// MODULES: <module name>
|
||||||
|
// ENUMS: {
|
||||||
|
// <enum name>: {
|
||||||
|
// type: <enum type>,
|
||||||
|
// description: <enum description>
|
||||||
|
// }, ...
|
||||||
|
// }
|
||||||
|
// ENUMS_BY_GROUP: {
|
||||||
|
// <enum type>: {
|
||||||
|
// description: <enum group description>
|
||||||
|
// members: [ <enum name>, ... ]
|
||||||
|
// }, ...
|
||||||
|
// }
|
||||||
|
// METHODS: {
|
||||||
|
// <method name>: {
|
||||||
|
// description: <method description>,
|
||||||
|
// params: {
|
||||||
|
// <param name>: {
|
||||||
|
// type: <param type>,
|
||||||
|
// description: <param description >
|
||||||
|
// }, ...
|
||||||
|
// },
|
||||||
|
// return: {
|
||||||
|
// type: <return type>,
|
||||||
|
// description: <return description>
|
||||||
|
// }
|
||||||
|
// }, ...
|
||||||
|
// }
|
||||||
|
// CLASSES: {
|
||||||
|
// <class name>: {
|
||||||
|
// description: <class description>,
|
||||||
|
// methods: { ... },
|
||||||
|
// variables: {
|
||||||
|
// <variable name>: {
|
||||||
|
// type: <variable type>,
|
||||||
|
// description: <variable description>
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// enums: { ... },
|
||||||
|
// enums_by_group: { ... }
|
||||||
|
// }, ...
|
||||||
|
// }
|
||||||
|
MODULE: '',
|
||||||
|
ENUMS: {},
|
||||||
|
ENUMS_BY_GROUP: {},
|
||||||
|
METHODS: {},
|
||||||
|
CLASSES: {},
|
||||||
|
|
||||||
|
|
||||||
|
// c -> js type mapping
|
||||||
|
TYPEMAPS: {
|
||||||
|
'^(const)?\\s*(unsigned|signed)?\\s*(int|short|long|float|double|size_t|u?int\\d{1,2}_t)?$': 'Number',
|
||||||
|
'^bool$': 'Boolean',
|
||||||
|
'^(const)?\\s*(unsigned|signed)?\\s*(char|char\\s*\\*|std::string)$': 'String' // TODO: verify that String mappings work
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
// add command line options for this module
|
||||||
|
addOptions: function(opts) {
|
||||||
|
xml2js.opts = opts;
|
||||||
|
return opts
|
||||||
|
.option('-i, --inputdir [directory]', 'directory for xml files', __dirname + '/xml/mraa')
|
||||||
|
.option('-c, --custom [file]', 'json for customizations', __dirname + '/custom.json')
|
||||||
|
.option('-s, --strict', 'leave out methods/variables if unknown type')
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
// parse doxygen xml -> js-format specs
|
||||||
|
// TODO: figure out whether we need to document any protected methods/variables
|
||||||
|
parse: function() {
|
||||||
|
var XML_GRAMMAR_SPEC = 'grammars/xml.peg';
|
||||||
|
var NAMESPACE_SPEC = xml2js.opts.inputdir + '/namespace' + xml2js.opts.module + '.xml';
|
||||||
|
var CLASS_SPEC = function(c) { return xml2js.opts.inputdir + '/' + c + '.xml'; }
|
||||||
|
var TYPES_SPEC = xml2js.opts.inputdir + '/types_8h.xml';
|
||||||
|
xml2js.MODULE = xml2js.opts.module;
|
||||||
|
return Promise.join(createXmlParser(XML_GRAMMAR_SPEC),
|
||||||
|
fs.readFileAsync(NAMESPACE_SPEC, 'utf8'),
|
||||||
|
fs.existsSync(TYPES_SPEC) ? fs.readFileAsync(TYPES_SPEC, 'utf8') : Promise.resolve(null),
|
||||||
|
function(xmlparser, xml, xml_types) {
|
||||||
|
if (xml_types != null) {
|
||||||
|
_.extend(xml2js.ENUMS, getEnums(xmlparser.parse(xml_types)[0], false));
|
||||||
|
_.extend(xml2js.ENUMS_BY_GROUP, getEnums(xmlparser.parse(xml_types)[0], true));
|
||||||
|
}
|
||||||
|
var spec_c = xmlparser.parse(xml)[0];
|
||||||
|
_.extend(xml2js.ENUMS, getEnums(spec_c, false));
|
||||||
|
_.extend(xml2js.ENUMS_BY_GROUP, getEnums(spec_c, true));
|
||||||
|
_.extend(xml2js.METHODS, getMethods(spec_c));
|
||||||
|
return Promise.all(_.map(getClasses(spec_c), function(c) {
|
||||||
|
return fs.readFileAsync(CLASS_SPEC(c), 'utf8').then(function(xml) {
|
||||||
|
try {
|
||||||
|
var spec_c = xmlparser.parse(xml)[0];
|
||||||
|
var className = getClassName(spec_c);
|
||||||
|
xml2js.CLASSES[className] = {
|
||||||
|
description: getClassDescription(spec_c),
|
||||||
|
enums: getEnums(spec_c, false, className),
|
||||||
|
enums_by_group: getEnums(spec_c, true, className),
|
||||||
|
variables: getVariables(spec_c, className),
|
||||||
|
methods: getMethods(spec_c, className),
|
||||||
|
};
|
||||||
|
} catch(e) {
|
||||||
|
console.log(e.toString() + ': ' + c + ' was not parsed correctly.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})).then(function() {
|
||||||
|
if (fs.existsSync(xml2js.opts.custom)) {
|
||||||
|
return fs.readFileAsync(xml2js.opts.custom, 'utf8').then(function(custom) {
|
||||||
|
try {
|
||||||
|
customizeMethods(JSON.parse(custom));
|
||||||
|
} catch(e) {
|
||||||
|
console.log('invalid custom.json, ignored. ' + e.toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log((xml2js.opts.custom == __dirname + '/custom.json') ? 'No customizations given.' : 'Error: No such customization file exists: ' + xml2js.opts.custom);
|
||||||
|
}
|
||||||
|
}).then(function() {
|
||||||
|
validateMethods();
|
||||||
|
validateVars();
|
||||||
|
return _.pick(xml2js, 'MODULE', 'ENUMS', 'ENUMS_BY_GROUP', 'METHODS', 'CLASSES');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// create an xml parser
|
||||||
|
function createXmlParser(XML_GRAMMAR_SPEC) {
|
||||||
|
return fs.readFileAsync(XML_GRAMMAR_SPEC, 'utf8').then(function(xmlgrammar) {
|
||||||
|
return peg.buildParser(xmlgrammar);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// override autogenerated methods with custom configuration
|
||||||
|
function customizeMethods(custom) {
|
||||||
|
_.each(custom, function(classMethods, className) {
|
||||||
|
_.extend(xml2js.CLASSES[className].methods, _.pick(classMethods, function(methodSpec, methodName) {
|
||||||
|
return isValidMethodSpec(methodSpec, className + '.' + methodName);
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure methods have valid types, otherwise warn (& don't include if strict)
|
||||||
|
function validateMethods() {
|
||||||
|
xml2js.METHODS = _.pick(xml2js.METHODS, function(methodSpec, methodName) {
|
||||||
|
hasValidTypes(methodSpec, methodName);
|
||||||
|
});
|
||||||
|
_.each(xml2js.CLASSES, function(classSpec, className) {
|
||||||
|
var valid = _.pick(classSpec.methods, function(methodSpec, methodName) {
|
||||||
|
return hasValidTypes(methodSpec, className + '.' + methodName, className);
|
||||||
|
});
|
||||||
|
if (xml2js.opts.strict) {
|
||||||
|
xml2js.CLASSES[className].methods = valid;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// make sure variables have valid types, otherwise warn (& don't include if strict)
|
||||||
|
function validateVars() {
|
||||||
|
_.each(xml2js.CLASSES, function(classSpec, className) {
|
||||||
|
var valid = _.pick(classSpec.variables, function(varSpec, varName) {
|
||||||
|
return ofValidType(varSpec, className + '.' + varName, className);
|
||||||
|
});
|
||||||
|
if (xml2js.opts.strict) {
|
||||||
|
xml2js.CLASSES[className].variables = valid;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// verify that the json spec is well formatted
|
||||||
|
function isValidMethodSpec(methodSpec, methodName) {
|
||||||
|
var valid = true;
|
||||||
|
var printIgnoredMethodOnce = _.once(function() { console.log(methodName + ' from ' + path.basename(xml2js.opts.custom) + ' is omitted from JS documentation.'); });
|
||||||
|
function checkRule(rule, errMsg) {
|
||||||
|
if (!rule) {
|
||||||
|
printIgnoredMethodOnce();
|
||||||
|
console.log(' ' + errMsg);
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkRule(_.has(methodSpec, 'description'), 'no description given');
|
||||||
|
checkRule(_.has(methodSpec, 'params'), 'no params given (specify "params": {} for no params)');
|
||||||
|
_.each(methodSpec.params, function(paramSpec, paramName) {
|
||||||
|
checkRule(_.has(paramSpec, 'type'), 'no type given for param ' + paramName);
|
||||||
|
checkRule(_.has(paramSpec, 'description'), 'no description given for param ' + paramName);
|
||||||
|
});
|
||||||
|
checkRule(_.has(methodSpec, 'return'), 'no return given (specify "return": {} for no return value)');
|
||||||
|
checkRule(_.has(methodSpec.return, 'type'), 'no type given for return value');
|
||||||
|
checkRule(_.has(methodSpec.return, 'description'), 'no description given for return value');
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get enum specifications
|
||||||
|
function getEnums(spec_c, bygroup, parent) {
|
||||||
|
var spec_js = {};
|
||||||
|
var enumGroups = _.find(getChildren(spec_c, 'sectiondef'), function(section) {
|
||||||
|
var kind = getAttr(section, 'kind');
|
||||||
|
return ((kind == 'enum') || (kind == 'public-type'));
|
||||||
|
});
|
||||||
|
if (enumGroups) {
|
||||||
|
_.each(enumGroups.children, function(enumGroup) {
|
||||||
|
var enumGroupName = getText(getChild(enumGroup, 'name'), 'name');
|
||||||
|
var enumGroupDescription = getText(getChild(enumGroup, 'detaileddescription'), 'description');
|
||||||
|
var enumGroupVals = getChildren(enumGroup, 'enumvalue');
|
||||||
|
if (bygroup) {
|
||||||
|
spec_js[enumGroupName] = {
|
||||||
|
description: enumGroupDescription,
|
||||||
|
members: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
_.each(enumGroupVals, function(e) {
|
||||||
|
// TODO: get prefix as option
|
||||||
|
var enumName = getText(getChild(e, 'name'), 'name').replace(/^MRAA_/, '');
|
||||||
|
var enumDescription = getText(getChild(e, 'detaileddescription'), 'description');
|
||||||
|
if (!bygroup) {
|
||||||
|
spec_js[enumName] = {
|
||||||
|
type: enumGroupName,
|
||||||
|
description: enumDescription
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
spec_js[enumGroupName].members.push(enumName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return spec_js;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get the classes (xml file names) for the given module
|
||||||
|
function getClasses(spec_c) {
|
||||||
|
return _.map(getChildren(spec_c, 'innerclass'), function(innerclass) {
|
||||||
|
return getAttr(innerclass, 'refid');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get the description of the class
|
||||||
|
function getClassDescription(spec_c) {
|
||||||
|
return getText(getChild(spec_c, 'detaileddescription'), 'description');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function hasParams(paramsSpec) {
|
||||||
|
return !(_.isEmpty(paramsSpec) ||
|
||||||
|
((_.size(paramsSpec) == 1) && getText(getChild(paramsSpec[0], 'type')) == 'void'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get method specifications for top-level module or a given class
|
||||||
|
// TODO: overloaded functions
|
||||||
|
// TODO: functions w/ invalid parameter(s)/return
|
||||||
|
function getMethods(spec_c, parent) {
|
||||||
|
var spec_js = {};
|
||||||
|
var methods = _.find(getChildren(spec_c, 'sectiondef'), function(section) {
|
||||||
|
var kind = getAttr(section, 'kind');
|
||||||
|
return ((kind == 'public-func') || (kind == 'func'));
|
||||||
|
});
|
||||||
|
if (methods) {
|
||||||
|
_.each(methods.children, function(method) {
|
||||||
|
var methodName = getText(getChild(method, 'name'), 'name');
|
||||||
|
if (methodName[0] != '~') { // filter out destructors
|
||||||
|
try {
|
||||||
|
var description = getChild(method, 'detaileddescription');
|
||||||
|
var methodDescription = getText(description, 'description');
|
||||||
|
var paramsSpec = getChildren(method, 'param');
|
||||||
|
var params = {};
|
||||||
|
if (hasParams(paramsSpec)) {
|
||||||
|
params = getParams(paramsSpec, getParamsDetails(description), (parent ? (parent + '.') : '') + methodName);
|
||||||
|
}
|
||||||
|
var returnSpec = getChild(method, 'type');
|
||||||
|
var retval = {};
|
||||||
|
if (!_.isEmpty(returnSpec)) {
|
||||||
|
retval = getReturn(returnSpec, getReturnDetails(description));
|
||||||
|
}
|
||||||
|
spec_js[methodName] = {
|
||||||
|
description: methodDescription,
|
||||||
|
params: params,
|
||||||
|
return: retval
|
||||||
|
};
|
||||||
|
} catch(e) {
|
||||||
|
console.log((parent ? (parent + '.') : '') + methodName + ' is omitted from JS documentation.');
|
||||||
|
console.log(' ' + e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return spec_js;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get variable specifications for a class
|
||||||
|
function getVariables(spec_c, parent) {
|
||||||
|
var spec_js = {};
|
||||||
|
var vars = _.find(getChildren(spec_c, 'sectiondef'), function(section) {
|
||||||
|
var kind = getAttr(section, 'kind');
|
||||||
|
return (kind == 'public-attrib');
|
||||||
|
});
|
||||||
|
if (vars) {
|
||||||
|
_.each(_.filter(vars.children, function(variable) {
|
||||||
|
return (getAttr(variable, 'kind') == 'variable');
|
||||||
|
}), function(variable) {
|
||||||
|
var varName = getText(getChild(variable, 'name'), 'name');
|
||||||
|
var varType = getType(getText(getChild(variable, 'type')));
|
||||||
|
var varDescription = getText(getChild(variable, 'detaileddescription'));
|
||||||
|
spec_js[varName] = {
|
||||||
|
type: varType,
|
||||||
|
description: varDescription
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return spec_js;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get return value specs of a method
|
||||||
|
function getReturn(spec_c, details) {
|
||||||
|
var retType = getType(getText(spec_c, 'type'));
|
||||||
|
var retDescription = (details ? getText(details, 'description') : '');
|
||||||
|
return ((retType == 'void') ? {} : {
|
||||||
|
type: retType,
|
||||||
|
description: retDescription
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get paramater specs of a method
|
||||||
|
function getParams(spec_c, details, method) {
|
||||||
|
var spec_js = {};
|
||||||
|
_.each(spec_c, function(param) {
|
||||||
|
try {
|
||||||
|
var paramType = getType(getText(getChild(param, 'type'), 'type'));
|
||||||
|
var paramName = getText(getChild(param, 'declname'), 'name');
|
||||||
|
spec_js[paramName] = { type: paramType };
|
||||||
|
} catch(e) {
|
||||||
|
if (paramType == '...') {
|
||||||
|
spec_js['arguments'] = { type: paramType };
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_.each(details, function(param) {
|
||||||
|
var getParamName = function(p) { return getText(getChild(getChild(p, 'parameternamelist'), 'parametername'), 'name'); }
|
||||||
|
var paramName = getParamName(param);
|
||||||
|
var paramDescription = getText(getChild(param, 'parameterdescription'), 'description');
|
||||||
|
if (_.has(spec_js, paramName)) {
|
||||||
|
spec_js[paramName].description = paramDescription;
|
||||||
|
} else {
|
||||||
|
var msg = ' has documentation for an unknown parameter: ' + paramName + '. ';
|
||||||
|
var suggestions = _.difference(_.keys(spec_js), _.map(details, getParamName));
|
||||||
|
var msgAddendum = (!_.isEmpty(suggestions) ? ('Did you mean ' + suggestions.join(', or ') + '?') : '');
|
||||||
|
console.log('Warning: ' + method + msg + msgAddendum);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return spec_js;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get the equivalent javascript type from the given c type
|
||||||
|
function getType(type_c) {
|
||||||
|
var type_js = type_c;
|
||||||
|
_.find(xml2js.TYPEMAPS, function(to, from) {
|
||||||
|
var pattern = new RegExp(from, 'i');
|
||||||
|
if (type_c.search(pattern) == 0) {
|
||||||
|
type_js = to;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// TODO: temporary solution
|
||||||
|
// remove extra whitespace from pointers
|
||||||
|
// permanent solution would be to get rid of pointers all together
|
||||||
|
if (type_js.search(/\S+\s*\*$/) != -1) {
|
||||||
|
type_js = type_js.replace(/\s*\*$/, '*');
|
||||||
|
}
|
||||||
|
return type_js;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// verify that all types associated with the method are valid
|
||||||
|
function hasValidTypes(methodSpec, methodName, parent) {
|
||||||
|
var valid = true;
|
||||||
|
var msg = (xml2js.opts.strict ? ' is omitted from JS documentation.' : ' has invalid type(s).');
|
||||||
|
var printIgnoredMethodOnce = _.once(function() { console.log(methodName + msg); });
|
||||||
|
_.each(methodSpec.params, function(paramSpec, paramName) {
|
||||||
|
if (!isValidType(paramSpec.type, parent)) {
|
||||||
|
valid = false;
|
||||||
|
printIgnoredMethodOnce();
|
||||||
|
console.log(' Error: parameter ' + paramName + ' has invalid type ' + paramSpec.type);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!_.isEmpty(methodSpec.return) && !isValidType(methodSpec.return.type, parent)) {
|
||||||
|
valid = false;
|
||||||
|
printIgnoredMethodOnce();
|
||||||
|
console.log(' Error: returns invalid type ' + methodSpec.return.type);
|
||||||
|
}
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// verify that type of variable is valid
|
||||||
|
function ofValidType(varSpec, varName, parent) {
|
||||||
|
if (isValidType(varSpec.type, parent)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
var msgAddendum = (xml2js.opts.strict ? ' Omitted from JS documentation.' : '');
|
||||||
|
console.log('Error: ' + varName + ' is of invalid type ' + varSpec.type + '.' + msgAddendum);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// verify whether the given type is valid JS
|
||||||
|
// TODO: check class-specific types
|
||||||
|
function isValidType(type, parent) {
|
||||||
|
return (_.contains(_.values(xml2js.TYPEMAPS), type) ||
|
||||||
|
_.has(xml2js.CLASSES, type) ||
|
||||||
|
_.has(xml2js.ENUMS_BY_GROUP, type) ||
|
||||||
|
_.contains(['Buffer', 'Function', 'mraa_result_t'], type) ||
|
||||||
|
_.has((parent ? xml2js.CLASSES[parent].enums_by_group : []), type));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// determines whether a type looks like a c pointer
|
||||||
|
function isPointer(type) {
|
||||||
|
return (type.search(/\w+\s*\*/) != -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get the detailed description of a method's parameters
|
||||||
|
function getParamsDetails(spec_c) {
|
||||||
|
var paras = getChildren(spec_c, 'para');
|
||||||
|
var details = _.find(_.map(paras, function(para) {
|
||||||
|
return getChild(para, 'parameterlist');
|
||||||
|
}), function(obj) { return (obj != undefined); });
|
||||||
|
return (details ? details.children : undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get the detailed description of a method's return value
|
||||||
|
function getReturnDetails(spec_c) {
|
||||||
|
var paras = getChildren(spec_c, 'para');
|
||||||
|
return _.find(_.map(paras, function(para) {
|
||||||
|
return getChild(para, 'simplesect');
|
||||||
|
}), function(obj) { return ((obj != undefined) && (getAttr(obj, 'kind') == 'return')); });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get (and flatten) the text of the given object
|
||||||
|
function getText(obj, why) {
|
||||||
|
// TODO: links ignored for now, patched for types for
|
||||||
|
var GENERATE_LINK = function(x) { return x + ' '; }
|
||||||
|
return _.reduce(obj.children, function(text, elem) {
|
||||||
|
if (_.isString(elem)) {
|
||||||
|
return text += elem.trim() + ' ';
|
||||||
|
} else if (_.isPlainObject(elem)) {
|
||||||
|
switch(elem.name) {
|
||||||
|
case 'para':
|
||||||
|
return text += getText(elem, why) + ' \n';
|
||||||
|
case 'ref':
|
||||||
|
return text += GENERATE_LINK(getText(elem, why));
|
||||||
|
case 'parameterlist':
|
||||||
|
case 'simplesect':
|
||||||
|
return text; // to be handled elsewhere
|
||||||
|
case 'programlisting':
|
||||||
|
case 'htmlonly':
|
||||||
|
return text; // ignored
|
||||||
|
// TODO: html doesn't seem to work, using markdown for now
|
||||||
|
case 'itemizedlist':
|
||||||
|
return text += '\n' + getText(elem, why) + '\n';
|
||||||
|
case 'listitem':
|
||||||
|
return text += '+ ' + getText(elem, why) + '\n';
|
||||||
|
case 'bold':
|
||||||
|
return text += '__' + getText(elem, why).trim() + '__ ';
|
||||||
|
case 'ulink':
|
||||||
|
return text += '[' + getText(elem, why).trim() + '](' + getAttr(elem, 'url').trim() + ') ';
|
||||||
|
case 'image':
|
||||||
|
// TODO: copy images over; hard coded for now
|
||||||
|
var fn = getAttr(elem, 'name');
|
||||||
|
return text += ' \n \n ';
|
||||||
|
case 'linebreak':
|
||||||
|
return text += ' \n';
|
||||||
|
case 'ndash':
|
||||||
|
return text += '– ';
|
||||||
|
default:
|
||||||
|
// TODO: incomplete list of doxygen xsd implemented
|
||||||
|
throw new Error('NYI Unknown Object Type: ' + elem.name);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error('NYI Unknown Type: ' + (typeof elem));
|
||||||
|
}
|
||||||
|
}, '').trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get the value of attribute with the given name of the given object
|
||||||
|
function getAttr(obj, name) {
|
||||||
|
return _.find(obj.attr, function(item) {
|
||||||
|
return item.name == name;
|
||||||
|
}).value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get the child object with the given name of the given object
|
||||||
|
function getChild(obj, name) {
|
||||||
|
return _.find(obj.children, function(child) {
|
||||||
|
return child.name == name;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get all children objects with the given name of the given object
|
||||||
|
function getChildren(obj, name) {
|
||||||
|
return _.filter(obj.children, function(child) {
|
||||||
|
return child.name == name;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get the class name from its xml spec
|
||||||
|
function getClassName(spec_c) {
|
||||||
|
return getText(getChild(spec_c, 'compoundname'), 'name').replace(xml2js.opts.module + '::', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// debug helper: print untruncated object
|
||||||
|
function printObj(obj) {
|
||||||
|
console.log(util.inspect(obj, false, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = xml2js;
|
Loading…
x
Reference in New Issue
Block a user