Browse Source

jsdoc: scripts for generating node.js documentation

Signed-off-by: Mihai Tudor Panu <mihai.tudor.panu@intel.com>
Mihai Tudor Panu 10 years ago
parent
commit
65a19d1779

+ 60
- 0
doxy/node/docgen.js View File

@@ -0,0 +1,60 @@
1
+/*
2
+ * Author: Heidi Pan <heidi.pan@intel.com>
3
+ * Copyright (c) 2015 Intel Corporation.
4
+ *
5
+ * Permission is hereby granted, free of charge, to any person obtaining
6
+ * a copy of this software and associated documentation files (the
7
+ * "Software"), to deal in the Software without restriction, including
8
+ * without limitation the rights to use, copy, modify, merge, publish,
9
+ * distribute, sublicense, and/or sell copies of the Software, and to
10
+ * permit persons to whom the Software is furnished to do so, subject to
11
+ * the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be
14
+ * included in all copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ */
24
+
25
+// dependencies
26
+var xml2js  = require('./xml2js')
27
+  , fs      = require('fs')
28
+  , Promise = require('bluebird')
29
+  , opts    = require('commander')
30
+  , _       = require('lodash')
31
+  , mkdirp  = require('mkdirp');
32
+
33
+
34
+// parse command line arguments
35
+_.extend(opts, { addOptions: function(module) { return module.addOptions(opts); } });
36
+opts
37
+  .option('-m, --module [module]', 'module name for which to build documentation', 'mraa')
38
+  .option('-f, --formats [formats]', 'format for js comments', 'jsdoc,yuidoc,ternjs')
39
+  .option('-o, --outdir [directory]', 'top directory to build documentation', __dirname + '/jsdoc')
40
+  .addOptions(xml2js)
41
+  .parse(process.argv);
42
+
43
+
44
+// use promise-style programming rather than spaghetti callbacks
45
+Promise.promisifyAll(fs);
46
+
47
+// TODO: create directory structure if doesn't exist
48
+var formats = opts.formats.split(',');
49
+formats.forEach(function(format){
50
+  mkdirp('jsdoc/' + format + '/' + opts.module);
51
+});
52
+
53
+// main
54
+xml2js.parse().then(function(specjs) {
55
+  Promise.all(_.map(formats, function(format) {
56
+    var generateDocs = require(__dirname + '/generators/' + format + '/generator');
57
+    var outFile = opts.outdir + '/' + format + '/' + specjs.MODULE + '/doc.js';
58
+    return fs.writeFileAsync(outFile, generateDocs(specjs));
59
+  }));
60
+});

+ 7
- 0
doxy/node/generators/jsdoc/conf.json View File

@@ -0,0 +1,7 @@
1
+{
2
+  "templates": {
3
+    "default": {
4
+      "outputSourceFiles": false
5
+    }
6
+  }
7
+}

+ 88
- 0
doxy/node/generators/jsdoc/generator.js View File

@@ -0,0 +1,88 @@
1
+/*
2
+ * Author: Heidi Pan <heidi.pan@intel.com>
3
+ * Copyright (c) 2015 Intel Corporation.
4
+ *
5
+ * Permission is hereby granted, free of charge, to any person obtaining
6
+ * a copy of this software and associated documentation files (the
7
+ * "Software"), to deal in the Software without restriction, including
8
+ * without limitation the rights to use, copy, modify, merge, publish,
9
+ * distribute, sublicense, and/or sell copies of the Software, and to
10
+ * permit persons to whom the Software is furnished to do so, subject to
11
+ * the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be
14
+ * included in all copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ */
24
+
25
+// dependencies
26
+var _ = require('lodash');
27
+
28
+
29
+// generate JSDoc-style documentation
30
+function generateDocs(specjs) {
31
+  var docs = GENERATE_MODULE(specjs.MODULE);
32
+  docs = _.reduce(specjs.METHODS, function(memo, methodSpec, methodName) {
33
+    return memo += GENERATE_METHOD(methodName, methodSpec);
34
+  }, docs);
35
+  docs = _.reduce(specjs.ENUMS, function(memo, enumSpec, enumName) {
36
+    return memo += GENERATE_ENUM(enumName, enumSpec);
37
+  }, docs);
38
+  docs = _.reduce(specjs.CLASSES, function(memo, classSpec, parentClass) {
39
+    return _.reduce(classSpec.methods, function(memo, methodSpec, methodName) {
40
+      return memo += GENERATE_METHOD(methodName, methodSpec, parentClass);
41
+    }, memo);
42
+  }, docs);
43
+  return docs;
44
+}
45
+
46
+
47
+// comment wrapper around entire spec
48
+function GENERATE_DOC(text) {
49
+  return '/**\n' + text + ' */\n';
50
+}
51
+
52
+
53
+// generate module spec
54
+function GENERATE_MODULE(module) {
55
+  return GENERATE_DOC('@module ' + module + '\n');
56
+}
57
+
58
+
59
+// generate method spec with parent module/class
60
+function GENERATE_METHOD(name, spec, parent) {
61
+  return GENERATE_DOC(spec.description + '\n'
62
+    + '@method ' + name + '\n'
63
+    + '@instance\n'
64
+    + (parent ? ('@memberof ' + parent + '\n') : '')
65
+    + _.reduce(spec.params, function(memo, paramSpec, paramName) {
66
+        return '@param {' + paramSpec.type + '} ' + paramName + ' ' + paramSpec.description + '\n';
67
+      }, '')
68
+    + ( !_.isEmpty(spec.return) ? ('@return {' + spec.return.type + '} ' + spec.return.description + '\n') : ''));
69
+}
70
+
71
+
72
+// generate enum spec
73
+function GENERATE_ENUM(name, spec) {
74
+  return GENERATE_DOC(spec.description + '\n\n'
75
+    + '@var ' + name + '\n'
76
+    + '@type Enum(' + spec.type + ')\n'
77
+    + '@instance\n');
78
+}
79
+
80
+
81
+// TODO
82
+// generate link spec
83
+function GENERATE_LINK(text) {
84
+    return '{@link ' + text + '}';
85
+}
86
+
87
+
88
+module.exports = generateDocs;

+ 110
- 0
doxy/node/generators/ternjs/generator.js View File

@@ -0,0 +1,110 @@
1
+/*
2
+ * Author: Heidi Pan <heidi.pan@intel.com>
3
+ * Copyright (c) 2015 Intel Corporation.
4
+ *
5
+ * Permission is hereby granted, free of charge, to any person obtaining
6
+ * a copy of this software and associated documentation files (the
7
+ * "Software"), to deal in the Software without restriction, including
8
+ * without limitation the rights to use, copy, modify, merge, publish,
9
+ * distribute, sublicense, and/or sell copies of the Software, and to
10
+ * permit persons to whom the Software is furnished to do so, subject to
11
+ * the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be
14
+ * included in all copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ */
24
+
25
+// dependencies
26
+var _ = require('lodash');
27
+
28
+
29
+// generate json for ternjs input
30
+function generateDocs(specjs) {
31
+  var docs = GENERATE_MODULE(specjs.MODULE);
32
+  GENERATE_TYPE = (function(enums) {
33
+    return function(type) {
34
+      return (_.contains(enums, type) ? ('Enum ' + type) : type);
35
+    }
36
+  })(_.keys(specjs.ENUMS_BY_GROUP));
37
+  _.each(specjs.ENUMS, function(enumSpec, enumName) {
38
+    _.extend(docs[specjs.MODULE], GENERATE_ENUM(enumName, enumSpec));
39
+  });
40
+  _.each(specjs.METHODS, function(methodSpec, methodName) {
41
+    _.extend(docs[specjs.MODULE], GENERATE_METHOD(methodName, methodSpec));
42
+  });
43
+  _.each(specjs.CLASSES, function(classSpec, parentClass) {
44
+    var constructor =  classSpec.methods[parentClass];
45
+    _.extend(docs[specjs.MODULE], GENERATE_METHOD(parentClass, constructor ? constructor : { params: {}, return: {}, description: '' } ));
46
+    _.each(classSpec.enums, function(enumSpec, enumName) {
47
+      _.extend(docs[specjs.MODULE][parentClass], GENERATE_ENUM(enumName, enumSpec));
48
+    });
49
+    docs[specjs.MODULE][parentClass].prototype = {};
50
+    _.each(_.omit(classSpec.methods, parentClass), function(methodSpec, methodName) {
51
+      _.extend(docs[specjs.MODULE][parentClass].prototype, GENERATE_METHOD(methodName, methodSpec));
52
+    });
53
+    _.each(classSpec.variables, function(variableSpec, variableName) {
54
+      _.extend(docs[specjs.MODULE][parentClass].prototype, GENERATE_VARIABLE(variableName, variableSpec));
55
+    });
56
+  });
57
+  return JSON.stringify(docs, null, 2);
58
+}
59
+
60
+
61
+// generate module spec
62
+function GENERATE_MODULE(module) {
63
+  var docs = { '!name': module + 'library' };
64
+  docs[module] = {};
65
+  return docs;
66
+}
67
+
68
+
69
+// generate method spec
70
+function GENERATE_METHOD(name, spec) {
71
+  var doc = {};
72
+  doc[name] = {
73
+    '!type': 'fn(' + GENERATE_PARAMS(spec.params) + ')' + GENERATE_RETURN(spec.return),
74
+    '!doc': spec.description
75
+  }
76
+  return doc;
77
+}
78
+
79
+
80
+// generate parameter signatures for method
81
+function GENERATE_PARAMS(spec) {
82
+  return _.map(spec, function(paramSpec, paramName) {
83
+    return paramName + ': ' + paramSpec.type;
84
+  }).join(', ');
85
+}
86
+
87
+
88
+// generate return signature for method
89
+function GENERATE_RETURN(spec) {
90
+  return (_.isEmpty(spec) ? '' : (' -> ' + spec.type));
91
+}
92
+
93
+
94
+// generate enum spec
95
+function GENERATE_ENUM(name, spec) {
96
+  var doc = {};
97
+  doc[name] = 'Enum ' + spec.type ;
98
+  return doc;
99
+}
100
+
101
+
102
+// generate variable spec
103
+function GENERATE_VARIABLE(name, spec) {
104
+  var doc = {};
105
+  doc[name]= spec.type ;
106
+  return doc;
107
+}
108
+
109
+
110
+module.exports = generateDocs;

+ 8
- 0
doxy/node/generators/yuidoc/conf.json View File

@@ -0,0 +1,8 @@
1
+{
2
+  "name": "UPM",
3
+  "description": "The UPM API: High Level Sensor Library for Intel IoT Devices Using MRAA",
4
+  "logo": "http://upload.wikimedia.org/wikipedia/commons/8/8c/Transparent.png",
5
+  "options": {
6
+    "outdir": "./html/node"
7
+  }
8
+}

+ 117
- 0
doxy/node/generators/yuidoc/generator.js View File

@@ -0,0 +1,117 @@
1
+/*
2
+ * Author: Heidi Pan <heidi.pan@intel.com>
3
+ * Copyright (c) 2015 Intel Corporation.
4
+ *
5
+ * Permission is hereby granted, free of charge, to any person obtaining
6
+ * a copy of this software and associated documentation files (the
7
+ * "Software"), to deal in the Software without restriction, including
8
+ * without limitation the rights to use, copy, modify, merge, publish,
9
+ * distribute, sublicense, and/or sell copies of the Software, and to
10
+ * permit persons to whom the Software is furnished to do so, subject to
11
+ * the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be
14
+ * included in all copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ */
24
+
25
+// dependencies
26
+var _ = require('lodash');
27
+
28
+
29
+// generate YuiDocs-style documentation
30
+function generateDocs(specjs) {
31
+  var docs = GENERATE_MODULE(specjs.MODULE);
32
+  GENERATE_TYPE = (function(enums) {
33
+    return function(type) {
34
+      return (_.contains(enums, type) ? ('Enum ' + type) : type);
35
+    }
36
+  })(_.keys(specjs.ENUMS_BY_GROUP));
37
+  docs = _.reduce(specjs.METHODS, function(memo, methodSpec, methodName) {
38
+    return memo += GENERATE_METHOD(methodName, methodSpec);
39
+  }, docs);
40
+  docs = _.reduce(specjs.ENUMS, function(memo, enumSpec, enumName) {
41
+    return memo += GENERATE_ENUM(enumName, enumSpec);
42
+  }, docs);
43
+  docs = _.reduce(specjs.CLASSES, function(memo, classSpec, parentClass) {
44
+    return memo
45
+      + GENERATE_CLASS(parentClass, classSpec.description)
46
+      + _.reduce(classSpec.methods, function(memo, methodSpec, methodName) {
47
+        return memo += GENERATE_METHOD(methodName, methodSpec, parentClass);
48
+      }, '')
49
+      + _.reduce(classSpec.variables, function(memo, variableSpec, variableName) {
50
+        return memo += GENERATE_VAR(variableName, variableSpec, parentClass);
51
+      }, '')
52
+      + _.reduce(classSpec.enums, function(memo, enumSpec, enumName) {
53
+        return memo += GENERATE_ENUM(enumName, enumSpec, parentClass);
54
+      }, '');
55
+  }, docs);
56
+  return docs;
57
+}
58
+
59
+
60
+
61
+// comment wrapper around entire spec
62
+function GENERATE_DOC(text) {
63
+  return '/**\n' + text + ' */\n';
64
+}
65
+
66
+
67
+// generate module spec
68
+function GENERATE_MODULE(module) {
69
+  return GENERATE_DOC('@module ' + module + '\n');
70
+}
71
+
72
+
73
+// generate class spec
74
+function GENERATE_CLASS(name, description) {
75
+  return GENERATE_DOC(description + '\n'
76
+    + '@class ' + name + '\n');
77
+}
78
+
79
+
80
+// generate method spec with parent module/class
81
+function GENERATE_METHOD(name, spec, parent) {
82
+  return GENERATE_DOC(spec.description + '\n'
83
+    + '@method ' + name + '\n'
84
+    + (parent ? ('@for ' + parent + '\n') : '@for common\n')
85
+    + _.reduce(spec.params, function(memo, paramSpec, paramName) {
86
+        return memo + '@param {' + GENERATE_TYPE(paramSpec.type) + '} ' + paramName + ' ' + paramSpec.description + '\n';
87
+      }, '')
88
+    + ( !_.isEmpty(spec.return) ? ('@return {' + GENERATE_TYPE(spec.return.type) + '} ' + spec.return.description + '\n') : ''));
89
+}
90
+
91
+
92
+// generate enum spec
93
+function GENERATE_ENUM(name, spec, parent) {
94
+  return GENERATE_DOC(spec.description + '\n'
95
+    + '@property ' + name + '\n'
96
+    + '@type Enum ' + spec.type + '\n'
97
+    + '@for ' + (parent ? parent : 'common') + '\n');
98
+}
99
+
100
+
101
+// generate variable specs
102
+function GENERATE_VAR(name, spec, parent) {
103
+  return GENERATE_DOC(spec.description + '\n'
104
+    + '@property ' + name + '\n'
105
+    + '@type ' + spec.type + '\n'
106
+    + '@for ' + parent + '\n');
107
+}
108
+
109
+
110
+// TODO
111
+// generate link spec
112
+function GENERATE_LINK(text) {
113
+  return '{{#crossLink "' + text + '"}}{{/crossLink}}';
114
+}
115
+
116
+
117
+module.exports = generateDocs;

+ 45
- 0
doxy/node/grammars/xml.peg View File

@@ -0,0 +1,45 @@
1
+document
2
+  = _ ignore* _ "<doxygen " _ attr:attr* _ ">" body:elements _ "</doxygen>" _ { return body; }
3
+
4
+
5
+elements
6
+  = element*
7
+
8
+element
9
+  = _ "<" startTag:id _ attr:attr* _ ">" _ children:elements _ "</" endTag:id ">" _ {
10
+    if (startTag != endTag) {
11
+      throw new Error("Expected </" + startTag + "> but </" + endTag + "> found.");
12
+    }
13
+    return {name: startTag, attr: attr, children: children }
14
+  }
15
+  / "<" tag:id _ attr:attr* _ "/>" _ {
16
+    return {name: tag, attr: attr }
17
+  }
18
+  / _ text:text _ { return text }
19
+
20
+ignore
21
+  = "<?xml" _ attr* _ "?>" { return }
22
+
23
+attr
24
+  = name:id _ "=" _ value:string { return { name:name, value:value } }
25
+
26
+string
27
+  = '"' '"' _           { return ""; }
28
+  / "'" "'" _           { return ""; }
29
+  / '"' text:quoted '"' _ { return text; }
30
+  / "'" text:quoted "'" _ { return text; }
31
+
32
+quoted
33
+  = chars:[^<>'" \t\n\r]+  { return chars.join(""); }
34
+
35
+text
36
+  = chars:[^<> \t\n\r]+  { return chars.join(""); }
37
+
38
+id
39
+  = chars:[^<>/'"=? \t\n\r]+  { return chars.join(""); }
40
+
41
+_ "whitespace"
42
+  = whitespace*
43
+
44
+whitespace
45
+  = [ \t\n\r]

+ 125
- 0
doxy/node/tolower.js View File

@@ -0,0 +1,125 @@
1
+/*
2
+ * Author: Dina M Suehiro <dina.m.suehiro@intel.com>
3
+ * Copyright (c) 2015 Intel Corporation.
4
+ *
5
+ * Permission is hereby granted, free of charge, to any person obtaining
6
+ * a copy of this software and associated documentation files (the
7
+ * "Software"), to deal in the Software without restriction, including
8
+ * without limitation the rights to use, copy, modify, merge, publish,
9
+ * distribute, sublicense, and/or sell copies of the Software, and to
10
+ * permit persons to whom the Software is furnished to do so, subject to
11
+ * the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be
14
+ * included in all copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ */
24
+
25
+// dependencies
26
+var opts    = require('commander'),     // for command line args
27
+    fs      = require('fs'),                // for file system access
28
+    path      = require('path');              // for file path parsing
29
+
30
+// parse command line arguments
31
+opts
32
+  .option('-i, --inputdir [directory]', 'product documents directory', __dirname + '/docs/yuidoc/upm')
33
+  .parse(process.argv);
34
+
35
+// Set to true for console output
36
+var debug = true;
37
+
38
+// Global arrays tracking the files that have been renamed
39
+var originalFiles = [];
40
+var renamedFiles = [];
41
+
42
+// Filter to get html files from different directories
43
+var rootFiles = getHtmlFilenames(opts.inputdir);
44
+var classesFiles = getHtmlFilenames(opts.inputdir + "/classes");
45
+var modulesFiles = getHtmlFilenames(opts.inputdir + "/modules");
46
+
47
+// Rename files in the classes directory to have lower-cased file names.
48
+renameFiles(classesFiles);
49
+
50
+classesFiles = getHtmlFilenames(opts.inputdir + "/classes");
51
+
52
+// Go through the html files and update links to reflect the file names that we changed.
53
+renameLinks(rootFiles);
54
+renameLinks(classesFiles);
55
+renameLinks(modulesFiles);
56
+
57
+// Helper function that returns paths to the html files in the specified directory
58
+function getHtmlFilenames (directory)
59
+{
60
+  return fs.readdirSync(directory).map(function (file) {
61
+    return path.join(directory, file);
62
+  }).filter(function (file) {
63
+    return fs.statSync(file).isFile();
64
+  }).filter(function (file) {
65
+    return path.extname(file).toLowerCase() == ".html";
66
+  });
67
+}
68
+
69
+// Goes through the files and renames them to be lower-cased and tracks them the
70
+// renamed files in the originalFiles[] and renamedFiles[] arrays.
71
+function renameFiles(files)
72
+{
73
+  files.forEach(function (file)
74
+  {
75
+    var originalName = path.basename(file);
76
+    var newFileName = originalName.toLowerCase();
77
+    var directory = path.dirname(file);
78
+    if (originalName != newFileName)
79
+    {
80
+      fs.renameSync(file, directory + "/" + newFileName); //, function(err)
81
+
82
+      if (debug)
83
+        console.log('Renamed: %s --> %s', originalName, newFileName);
84
+
85
+      originalFiles.push(originalName);
86
+      renamedFiles.push(newFileName);
87
+    }
88
+  });
89
+}
90
+
91
+// Helper function goes through the specified files and does a file/replace of the
92
+// originalFiles to the renamedFiles so that the .html links match what has been renamed.
93
+function renameLinks (files)
94
+{
95
+  if (originalFiles.length <= 0)
96
+  {
97
+    if (debug)
98
+      console.log("No links to rename.");
99
+    return;
100
+  }
101
+
102
+  files.forEach(function (file)
103
+  {
104
+    // Read the file
105
+    data = fs.readFileSync(file, 'ascii');
106
+
107
+    // Find/replace the file names that were renamed
108
+    for (var i = 0; i < originalFiles.length; i++)
109
+    {
110
+      var findString = '/' + originalFiles[i] + '\"';
111
+      var replaceString = '/' + renamedFiles[i] + '\"';
112
+
113
+      data = data.replace(findString, replaceString);
114
+    }
115
+
116
+    // Write back
117
+    fs.writeFile(file, data, 'ascii', function (err) {
118
+      if (err)
119
+        throw err;
120
+    });
121
+
122
+    if (debug)
123
+      console.log('Renamed links in: %s', file);
124
+  });
125
+}

+ 575
- 0
doxy/node/xml2js.js View File

@@ -0,0 +1,575 @@
1
+/*
2
+ * Author: Heidi Pan <heidi.pan@intel.com>
3
+ * Copyright (c) 2015 Intel Corporation.
4
+ *
5
+ * Permission is hereby granted, free of charge, to any person obtaining
6
+ * a copy of this software and associated documentation files (the
7
+ * "Software"), to deal in the Software without restriction, including
8
+ * without limitation the rights to use, copy, modify, merge, publish,
9
+ * distribute, sublicense, and/or sell copies of the Software, and to
10
+ * permit persons to whom the Software is furnished to do so, subject to
11
+ * the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be
14
+ * included in all copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ */
24
+
25
+// dependencies
26
+var peg     = require('pegjs')
27
+  , fs      = require('fs')
28
+  , path    = require('path')
29
+  , Promise = require('bluebird')
30
+  , _       = require('lodash')
31
+  , util    = require('util');
32
+
33
+
34
+// use promise-style programming rather than spaghetti callbacks
35
+Promise.promisifyAll(fs);
36
+
37
+
38
+var xml2js = {
39
+
40
+  // js-format specs
41
+  // MODULES: <module name>
42
+  // ENUMS: {
43
+  //   <enum name>: {
44
+  //     type: <enum type>,
45
+  //     description: <enum description>
46
+  //   }, ...
47
+  // }
48
+  // ENUMS_BY_GROUP: {
49
+  //   <enum type>: {
50
+  //     description: <enum group description>
51
+  //     members: [ <enum name>, ... ]
52
+  //   }, ...
53
+  // }
54
+  // METHODS: {
55
+  //   <method name>: {
56
+  //     description: <method description>,
57
+  //     params: {
58
+  //       <param name>: {
59
+  //         type: <param type>,
60
+  //         description: <param description >
61
+  //       }, ...
62
+  //     },
63
+  //     return: {
64
+  //       type: <return type>,
65
+  //       description: <return description>
66
+  //     }
67
+  //   }, ...
68
+  // }
69
+  // CLASSES: {
70
+  //   <class name>: {
71
+  //     description: <class description>,
72
+  //     methods: { ... },
73
+  //     variables: {
74
+  //       <variable name>: {
75
+  //         type: <variable type>,
76
+  //         description: <variable description>
77
+  //       }
78
+  //     },
79
+  //     enums: { ... },
80
+  //     enums_by_group: { ... }
81
+  //   }, ...
82
+  // }
83
+  MODULE: '',
84
+  ENUMS: {},
85
+  ENUMS_BY_GROUP: {},
86
+  METHODS: {},
87
+  CLASSES: {},
88
+
89
+
90
+  // c -> js type mapping
91
+  TYPEMAPS: {
92
+    '^(const)?\\s*(unsigned|signed)?\\s*(int|short|long|float|double|size_t|u?int\\d{1,2}_t)?$': 'Number',
93
+    '^bool$': 'Boolean',
94
+    '^(const)?\\s*(unsigned|signed)?\\s*(char|char\\s*\\*|std::string)$': 'String'  // TODO: verify that String mappings work
95
+  },
96
+
97
+
98
+  // add command line options for this module
99
+  addOptions: function(opts) {
100
+    xml2js.opts = opts;
101
+    return opts
102
+      .option('-i, --inputdir [directory]', 'directory for xml files', __dirname + '/xml/mraa')
103
+      .option('-c, --custom [file]', 'json for customizations', __dirname + '/custom.json')
104
+      .option('-s, --strict', 'leave out methods/variables if unknown type')
105
+  },
106
+
107
+
108
+  // parse doxygen xml -> js-format specs
109
+  // TODO: figure out whether we need to document any protected methods/variables
110
+  parse: function() {
111
+    var XML_GRAMMAR_SPEC = 'grammars/xml.peg';
112
+    var NAMESPACE_SPEC = xml2js.opts.inputdir + '/namespace' + xml2js.opts.module + '.xml';
113
+    var CLASS_SPEC = function(c) { return xml2js.opts.inputdir + '/' + c + '.xml'; }
114
+    var TYPES_SPEC = xml2js.opts.inputdir + '/types_8h.xml';
115
+    xml2js.MODULE = xml2js.opts.module;
116
+    return Promise.join(createXmlParser(XML_GRAMMAR_SPEC),
117
+                        fs.readFileAsync(NAMESPACE_SPEC, 'utf8'),
118
+                        fs.existsSync(TYPES_SPEC) ? fs.readFileAsync(TYPES_SPEC, 'utf8') : Promise.resolve(null),
119
+                        function(xmlparser, xml, xml_types) {
120
+      if (xml_types != null) {
121
+        _.extend(xml2js.ENUMS, getEnums(xmlparser.parse(xml_types)[0], false));
122
+        _.extend(xml2js.ENUMS_BY_GROUP, getEnums(xmlparser.parse(xml_types)[0], true));
123
+      }
124
+      var spec_c = xmlparser.parse(xml)[0];
125
+      _.extend(xml2js.ENUMS, getEnums(spec_c, false));
126
+      _.extend(xml2js.ENUMS_BY_GROUP, getEnums(spec_c, true));
127
+      _.extend(xml2js.METHODS, getMethods(spec_c));
128
+      return Promise.all(_.map(getClasses(spec_c), function(c) {
129
+        return fs.readFileAsync(CLASS_SPEC(c), 'utf8').then(function(xml) {
130
+          try {
131
+            var spec_c = xmlparser.parse(xml)[0];
132
+            var className = getClassName(spec_c);
133
+            xml2js.CLASSES[className] = {
134
+              description: getClassDescription(spec_c),
135
+              enums: getEnums(spec_c, false, className),
136
+              enums_by_group: getEnums(spec_c, true, className),
137
+              variables: getVariables(spec_c, className),
138
+              methods: getMethods(spec_c, className),
139
+            };
140
+          } catch(e) {
141
+            console.log(e.toString() + ': ' + c + ' was not parsed correctly.');
142
+          }
143
+        });
144
+      })).then(function() {
145
+        if (fs.existsSync(xml2js.opts.custom)) {
146
+          return fs.readFileAsync(xml2js.opts.custom, 'utf8').then(function(custom) {
147
+            try {
148
+              customizeMethods(JSON.parse(custom));
149
+            } catch(e) {
150
+              console.log('invalid custom.json, ignored. ' + e.toString());
151
+            }
152
+          });
153
+        } else {
154
+          console.log((xml2js.opts.custom == __dirname + '/custom.json') ? 'No customizations given.' : 'Error: No such customization file exists: ' + xml2js.opts.custom);
155
+        }
156
+      }).then(function() {
157
+        validateMethods();
158
+        validateVars();
159
+        return _.pick(xml2js, 'MODULE', 'ENUMS', 'ENUMS_BY_GROUP', 'METHODS', 'CLASSES');
160
+      });
161
+    });
162
+  }
163
+
164
+};
165
+
166
+
167
+// create an xml parser
168
+function createXmlParser(XML_GRAMMAR_SPEC) {
169
+  return fs.readFileAsync(XML_GRAMMAR_SPEC, 'utf8').then(function(xmlgrammar) {
170
+    return peg.buildParser(xmlgrammar);
171
+  });
172
+}
173
+
174
+
175
+// override autogenerated methods with custom configuration
176
+function customizeMethods(custom) {
177
+  _.each(custom, function(classMethods, className) {
178
+    _.extend(xml2js.CLASSES[className].methods, _.pick(classMethods, function(methodSpec, methodName) {
179
+      return isValidMethodSpec(methodSpec, className + '.' + methodName);
180
+    }));
181
+  });
182
+}
183
+
184
+// make sure methods have valid types, otherwise warn (& don't include if strict)
185
+function validateMethods() {
186
+  xml2js.METHODS = _.pick(xml2js.METHODS, function(methodSpec, methodName) {
187
+    hasValidTypes(methodSpec, methodName);
188
+  });
189
+  _.each(xml2js.CLASSES, function(classSpec, className) {
190
+    var valid = _.pick(classSpec.methods, function(methodSpec, methodName) {
191
+      return hasValidTypes(methodSpec, className + '.' + methodName, className);
192
+    });
193
+    if (xml2js.opts.strict) {
194
+      xml2js.CLASSES[className].methods = valid;
195
+    }
196
+  });
197
+}
198
+
199
+
200
+// make sure variables have valid types, otherwise warn (& don't include if strict)
201
+function validateVars() {
202
+  _.each(xml2js.CLASSES, function(classSpec, className) {
203
+    var valid = _.pick(classSpec.variables, function(varSpec, varName) {
204
+      return ofValidType(varSpec, className + '.' + varName, className);
205
+    });
206
+    if (xml2js.opts.strict) {
207
+      xml2js.CLASSES[className].variables = valid;
208
+    }
209
+  });
210
+}
211
+
212
+
213
+// verify that the json spec is well formatted
214
+function isValidMethodSpec(methodSpec, methodName) {
215
+  var valid = true;
216
+  var printIgnoredMethodOnce = _.once(function() { console.log(methodName + ' from ' + path.basename(xml2js.opts.custom) + ' is omitted from JS documentation.'); });
217
+  function checkRule(rule, errMsg) {
218
+    if (!rule) {
219
+      printIgnoredMethodOnce();
220
+      console.log('  ' + errMsg);
221
+      valid = false;
222
+    }
223
+  }
224
+  checkRule(_.has(methodSpec, 'description'), 'no description given');
225
+  checkRule(_.has(methodSpec, 'params'), 'no params given (specify "params": {} for no params)');
226
+  _.each(methodSpec.params, function(paramSpec, paramName) {
227
+    checkRule(_.has(paramSpec, 'type'), 'no type given for param ' + paramName);
228
+    checkRule(_.has(paramSpec, 'description'), 'no description given for param ' + paramName);
229
+  });
230
+  checkRule(_.has(methodSpec, 'return'), 'no return given (specify "return": {} for no return value)');
231
+  checkRule(_.has(methodSpec.return, 'type'), 'no type given for return value');
232
+  checkRule(_.has(methodSpec.return, 'description'), 'no description given for return value');
233
+  return valid;
234
+}
235
+
236
+
237
+// get enum specifications
238
+function getEnums(spec_c, bygroup, parent) {
239
+  var spec_js = {};
240
+  var enumGroups = _.find(getChildren(spec_c, 'sectiondef'), function(section) {
241
+    var kind = getAttr(section, 'kind');
242
+    return ((kind == 'enum') || (kind == 'public-type'));
243
+  });
244
+  if (enumGroups) {
245
+    _.each(enumGroups.children, function(enumGroup) {
246
+      var enumGroupName = getText(getChild(enumGroup, 'name'), 'name');
247
+      var enumGroupDescription = getText(getChild(enumGroup, 'detaileddescription'), 'description');
248
+      var enumGroupVals = getChildren(enumGroup, 'enumvalue');
249
+      if (bygroup) {
250
+        spec_js[enumGroupName] = {
251
+          description: enumGroupDescription,
252
+          members: []
253
+        };
254
+      }
255
+      _.each(enumGroupVals, function(e) {
256
+        // TODO: get prefix as option
257
+        var enumName = getText(getChild(e, 'name'), 'name').replace(/^MRAA_/, '');
258
+        var enumDescription = getText(getChild(e, 'detaileddescription'), 'description');
259
+        if (!bygroup) {
260
+          spec_js[enumName] = {
261
+            type: enumGroupName,
262
+            description: enumDescription
263
+          };
264
+        } else {
265
+          spec_js[enumGroupName].members.push(enumName);
266
+        }
267
+      });
268
+    });
269
+  }
270
+  return spec_js;
271
+}
272
+
273
+
274
+// get the classes (xml file names) for the given module
275
+function getClasses(spec_c) {
276
+  return _.map(getChildren(spec_c, 'innerclass'), function(innerclass) {
277
+    return getAttr(innerclass, 'refid');
278
+  });
279
+}
280
+
281
+
282
+// get the description of the class
283
+function getClassDescription(spec_c) {
284
+  return getText(getChild(spec_c, 'detaileddescription'), 'description');
285
+}
286
+
287
+
288
+function hasParams(paramsSpec) {
289
+  return !(_.isEmpty(paramsSpec) ||
290
+           ((_.size(paramsSpec) == 1) && getText(getChild(paramsSpec[0], 'type')) == 'void'));
291
+}
292
+
293
+
294
+// get method specifications for top-level module or a given class
295
+// TODO: overloaded functions
296
+// TODO: functions w/ invalid parameter(s)/return
297
+function getMethods(spec_c, parent) {
298
+  var spec_js = {};
299
+  var methods = _.find(getChildren(spec_c, 'sectiondef'), function(section) {
300
+    var kind = getAttr(section, 'kind');
301
+    return ((kind == 'public-func') || (kind == 'func'));
302
+  });
303
+  if (methods) {
304
+    _.each(methods.children, function(method) {
305
+      var methodName = getText(getChild(method, 'name'), 'name');
306
+      if (methodName[0] != '~') { // filter out destructors
307
+        try {
308
+          var description = getChild(method, 'detaileddescription');
309
+          var methodDescription = getText(description, 'description');
310
+          var paramsSpec = getChildren(method, 'param');
311
+          var params = {};
312
+          if (hasParams(paramsSpec)) {
313
+              params = getParams(paramsSpec, getParamsDetails(description), (parent ? (parent + '.') : '') + methodName);
314
+          }
315
+          var returnSpec = getChild(method, 'type');
316
+          var retval = {};
317
+          if (!_.isEmpty(returnSpec)) {
318
+            retval = getReturn(returnSpec, getReturnDetails(description));
319
+          }
320
+          spec_js[methodName] = {
321
+            description: methodDescription,
322
+            params: params,
323
+            return: retval
324
+          };
325
+        } catch(e) {
326
+          console.log((parent ? (parent + '.') : '') + methodName + ' is omitted from JS documentation.');
327
+          console.log('  ' + e.toString());
328
+        }
329
+      }
330
+    });
331
+  }
332
+  return spec_js;
333
+}
334
+
335
+
336
+// get variable specifications for a class
337
+function getVariables(spec_c, parent) {
338
+  var spec_js = {};
339
+  var vars = _.find(getChildren(spec_c, 'sectiondef'), function(section) {
340
+    var kind = getAttr(section, 'kind');
341
+    return (kind == 'public-attrib');
342
+  });
343
+  if (vars) {
344
+    _.each(_.filter(vars.children, function(variable) {
345
+      return (getAttr(variable, 'kind') == 'variable');
346
+    }), function(variable) {
347
+      var varName = getText(getChild(variable, 'name'), 'name');
348
+      var varType = getType(getText(getChild(variable, 'type')));
349
+      var varDescription = getText(getChild(variable, 'detaileddescription'));
350
+      spec_js[varName] = {
351
+        type: varType,
352
+        description: varDescription
353
+      }
354
+    });
355
+  }
356
+  return spec_js;
357
+}
358
+
359
+
360
+// get return value specs of a method
361
+function getReturn(spec_c, details) {
362
+  var retType = getType(getText(spec_c, 'type'));
363
+  var retDescription = (details ? getText(details, 'description') : '');
364
+  return ((retType == 'void') ? {} : {
365
+    type: retType,
366
+    description: retDescription
367
+  });
368
+}
369
+
370
+
371
+// get paramater specs of a method
372
+function getParams(spec_c, details, method) {
373
+  var spec_js = {};
374
+  _.each(spec_c, function(param) {
375
+    try {
376
+      var paramType = getType(getText(getChild(param, 'type'), 'type'));
377
+      var paramName = getText(getChild(param, 'declname'), 'name');
378
+      spec_js[paramName] = { type: paramType };
379
+    } catch(e) {
380
+      if (paramType == '...') {
381
+        spec_js['arguments'] = { type: paramType };
382
+      } else {
383
+        throw e;
384
+      }
385
+    }
386
+  });
387
+  _.each(details, function(param) {
388
+    var getParamName = function(p) { return getText(getChild(getChild(p, 'parameternamelist'), 'parametername'), 'name'); }
389
+    var paramName = getParamName(param);
390
+    var paramDescription = getText(getChild(param, 'parameterdescription'), 'description');
391
+    if (_.has(spec_js, paramName)) {
392
+      spec_js[paramName].description = paramDescription;
393
+    } else {
394
+      var msg = ' has documentation for an unknown parameter: ' + paramName + '. ';
395
+      var suggestions = _.difference(_.keys(spec_js), _.map(details, getParamName));
396
+      var msgAddendum = (!_.isEmpty(suggestions) ? ('Did you mean ' + suggestions.join(', or ') + '?') : '');
397
+      console.log('Warning: ' + method + msg + msgAddendum);
398
+    }
399
+  });
400
+  return spec_js;
401
+}
402
+
403
+
404
+// get the equivalent javascript type from the given c type
405
+function getType(type_c) {
406
+  var type_js = type_c;
407
+  _.find(xml2js.TYPEMAPS, function(to, from) {
408
+    var pattern = new RegExp(from, 'i');
409
+    if (type_c.search(pattern) == 0) {
410
+      type_js = to;
411
+    }
412
+  });
413
+  // TODO: temporary solution
414
+  // remove extra whitespace from pointers
415
+  // permanent solution would be to get rid of pointers all together
416
+  if (type_js.search(/\S+\s*\*$/) != -1) {
417
+    type_js = type_js.replace(/\s*\*$/, '*');
418
+  }
419
+  return type_js;
420
+}
421
+
422
+
423
+// verify that all types associated with the method are valid
424
+function hasValidTypes(methodSpec, methodName, parent) {
425
+  var valid = true;
426
+  var msg = (xml2js.opts.strict ? ' is omitted from JS documentation.' : ' has invalid type(s).');
427
+  var printIgnoredMethodOnce = _.once(function() { console.log(methodName + msg); });
428
+  _.each(methodSpec.params, function(paramSpec, paramName) {
429
+    if (!isValidType(paramSpec.type, parent)) {
430
+      valid = false;
431
+      printIgnoredMethodOnce();
432
+      console.log('  Error: parameter ' + paramName + ' has invalid type ' + paramSpec.type);
433
+    }
434
+  });
435
+  if (!_.isEmpty(methodSpec.return) && !isValidType(methodSpec.return.type, parent)) {
436
+    valid = false;
437
+    printIgnoredMethodOnce();
438
+    console.log('  Error: returns invalid type ' + methodSpec.return.type);
439
+  }
440
+  return valid;
441
+}
442
+
443
+
444
+// verify that type of variable is valid
445
+function ofValidType(varSpec, varName, parent) {
446
+  if (isValidType(varSpec.type, parent)) {
447
+    return true;
448
+  } else {
449
+    var msgAddendum = (xml2js.opts.strict ? ' Omitted from JS documentation.' : '');
450
+    console.log('Error: ' + varName + ' is of invalid type ' + varSpec.type + '.' + msgAddendum);
451
+    return false;
452
+  }
453
+}
454
+
455
+
456
+// verify whether the given type is valid JS
457
+// TODO: check class-specific types
458
+function isValidType(type, parent) {
459
+  return (_.contains(_.values(xml2js.TYPEMAPS), type) ||
460
+          _.has(xml2js.CLASSES, type) ||
461
+          _.has(xml2js.ENUMS_BY_GROUP, type) ||
462
+          _.contains(['Buffer', 'Function', 'mraa_result_t'], type) ||
463
+          _.has((parent ? xml2js.CLASSES[parent].enums_by_group : []), type));
464
+}
465
+
466
+
467
+// determines whether a type looks like a c pointer
468
+function isPointer(type) {
469
+  return (type.search(/\w+\s*\*/) != -1);
470
+}
471
+
472
+
473
+// get the detailed description of a method's parameters
474
+function getParamsDetails(spec_c) {
475
+  var paras = getChildren(spec_c, 'para');
476
+  var details = _.find(_.map(paras, function(para) {
477
+    return getChild(para, 'parameterlist');
478
+  }), function(obj) { return (obj != undefined); });
479
+  return (details ? details.children : undefined);
480
+}
481
+
482
+
483
+// get the detailed description of a method's return value
484
+function  getReturnDetails(spec_c) {
485
+  var paras = getChildren(spec_c, 'para');
486
+  return _.find(_.map(paras, function(para) {
487
+    return getChild(para, 'simplesect');
488
+  }), function(obj) { return ((obj != undefined) && (getAttr(obj, 'kind') == 'return')); });
489
+}
490
+
491
+
492
+// get (and flatten) the text of the given object
493
+function getText(obj, why) {
494
+  // TODO: links ignored for now, patched for types for
495
+  var GENERATE_LINK = function(x) { return x + ' '; }
496
+  return _.reduce(obj.children, function(text, elem) {
497
+    if (_.isString(elem)) {
498
+      return text += elem.trim() + ' ';
499
+    } else if (_.isPlainObject(elem)) {
500
+      switch(elem.name) {
501
+        case 'para':
502
+          return text += getText(elem, why) + '  \n';
503
+        case 'ref':
504
+          return text += GENERATE_LINK(getText(elem, why));
505
+        case 'parameterlist':
506
+        case 'simplesect':
507
+          return text; // to be handled elsewhere
508
+        case 'programlisting':
509
+        case 'htmlonly':
510
+          return text; // ignored
511
+        // TODO: html doesn't seem to work, using markdown for now
512
+        case 'itemizedlist':
513
+          return text += '\n' + getText(elem, why) + '\n';
514
+        case 'listitem':
515
+          return text += '+ ' + getText(elem, why) + '\n';
516
+        case 'bold':
517
+          return text += '__' + getText(elem, why).trim() + '__ ';
518
+        case 'ulink':
519
+          return text += '[' + getText(elem, why).trim() + '](' + getAttr(elem, 'url').trim() + ') ';
520
+        case 'image':
521
+          // TODO: copy images over; hard coded for now
522
+          var fn = getAttr(elem, 'name');
523
+          return text += '  \n  \n![' + fn + '](' + '../../../../docs/images/' + fn + ') ';
524
+        case 'linebreak':
525
+          return text += '  \n';
526
+        case 'ndash':
527
+          return text += '&ndash; ';
528
+        default:
529
+          // TODO: incomplete list of doxygen xsd implemented
530
+          throw new Error('NYI Unknown Object Type: ' + elem.name);
531
+      }
532
+    } else {
533
+      throw new Error('NYI Unknown Type: ' + (typeof elem));
534
+    }
535
+  }, '').trim();
536
+}
537
+
538
+
539
+// get the value of attribute with the given name of the given object
540
+function getAttr(obj, name) {
541
+  return _.find(obj.attr, function(item) {
542
+    return item.name == name;
543
+  }).value;
544
+}
545
+
546
+
547
+// get the child object with the given name of the given object
548
+function getChild(obj, name) {
549
+  return _.find(obj.children, function(child) {
550
+    return child.name == name;
551
+  });
552
+}
553
+
554
+
555
+// get all children objects with the given name of the given object
556
+function getChildren(obj, name) {
557
+  return _.filter(obj.children, function(child) {
558
+    return child.name == name;
559
+  });
560
+}
561
+
562
+
563
+// get the class name from its xml spec
564
+function getClassName(spec_c) {
565
+  return getText(getChild(spec_c, 'compoundname'), 'name').replace(xml2js.opts.module + '::', '');
566
+}
567
+
568
+
569
+// debug helper: print untruncated object
570
+function printObj(obj) {
571
+  console.log(util.inspect(obj, false, null));
572
+}
573
+
574
+
575
+module.exports = xml2js;