mirror of
				https://github.com/eclipse/upm.git
				synced 2025-10-30 06:34:58 +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:
		
							
								
								
									
										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; | ||||||
		Reference in New Issue
	
	Block a user
	 Mihai Tudor Panu
					Mihai Tudor Panu