Skip to content
This repository has been archived by the owner on Oct 9, 2020. It is now read-only.

Commit

Permalink
Browse files Browse the repository at this point in the history
Add support for function extractor
  • Loading branch information
gjtorikian committed Nov 5, 2012
1 parent 889c108 commit 3cbba61
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 5 deletions.
1 change: 0 additions & 1 deletion lib/panino.js
Expand Up @@ -486,7 +486,6 @@ Panino.render = function render(name, ast, buildOptions, callback) {
renderers[name](ast, options, callback);
};


/**
* Panino.cli -> cli
**/
Expand Down
2 changes: 1 addition & 1 deletion lib/panino/parsers.js
@@ -1,5 +1,5 @@
'use strict';

// Simple "shared" parsers object.
// Used to avoid circular dependencies (between cli and ndoc).
// Used to avoid circular dependencies (between cli and Panino).
module.exports = {};
189 changes: 189 additions & 0 deletions lib/panino/plugins/parsers/javascript/jsd/function_extractor.js
@@ -0,0 +1,189 @@
(function() {
var util = require('util');
var esprima, getFunctions, traverse;

esprima = require('esprima');

traverse = function(object, visitor, master) {
var parent;
parent = master === 'undefined' ? [] : master;
if (visitor.call(null, object, parent) === false) {
return;
}
return Object.keys(object).forEach(function(key) {
var child, path;
child = object[key];
path = [object];
path.push(parent);
if (typeof child === 'object' && child !== null) {
return traverse(child, visitor, path);
}
});
};

getFunctions = function(tree, code) {
var matched = false, list = [];
traverse(tree, function(node, path) {
var parent;
if (node.type === 'FunctionDeclaration') {
return list.push({
name: node.id.name,
params: node.params,
range: node.range,
blockStart: node.body.range[0],
end: node.body.range[1]
});
} else if (node.type === 'FunctionExpression') {
parent = path[0];
if (parent.type === 'AssignmentExpression') {
if (typeof parent.left.range !== 'undefined') {
if (parent.left.type === "MemberExpression") {

// for: foo.doSomething = function
if (parent.left.object.name !== undefined) {
var namespace = parent.left.object.name;

if (parent.left.property.name !== undefined) {
var memberName = parent.left.property.name;
matched = true;
}

// for: foo["doSomething"] = function()
else if (parent.left.property && parent.left.property.type === "Literal") {
var namespace = parent.left.object.name;
var memberName = parent.left.property.value;
matched = true;
}
}

// for: this.doSomething = function
else if (parent.left.object.type === "ThisExpression") {
var namespace = "thiz";
if (parent.left.property.name !== undefined) {
var memberName = parent.left.property.name;
matched = true;
}

// for this[variable] = function()
else if (parent.left.property.type === "CallExpression") {
// no op
matched = true;
}
}

// for: Function.prototype.doSomething = function()
else if (parent.left.object.object !== undefined && parent.left.object.object.type === "Identifier") {
var namespace = parent.left.object.object.type;
var memberName = parent.left.property.name;
var isPrototype = true;
var prototyping = "prototype";
matched = true;
}

// for: this.htmlElement.onmouseover = function()
else if (parent.left.type === "MemberExpression" && parent.left.object.type === "MemberExpression") {
var namespace ="thiz";
var memberName = parent.left.property.name;

var isPrototype = true;
var prototyping = parent.left.object.property.name;
matched = true;
}

// for: (boolType ? "name" : "name2").doSomething = function()
else if (parent.left.object !== undefined && parent.left.object.type === "ConditionalExpression") {
// no op
matched = true;
}
}
else if (parent.left.type === "Identifier") {
var memberName = parent.left.name;
matched = true;
}

if (!matched) {
console.error("Never found a matching arrangement!");
console.error(util.inspect(parent.left, null, 5));
}
else {
return list.push({
namespace: namespace,
name: memberName,
isPrototype: isPrototype,
prototyping: prototyping,
params: node.params,
range: node.range,
blockStart: node.body.range[0],
end: node.body.range[1]
});
}
}
} else if (parent.type === 'VariableDeclarator') {
return list.push({
name: parent.id.name,
params: node.params,
range: node.range,
blockStart: node.body.range[0],
end: node.body.range[1]
});
} else if (parent.type === 'CallExpression') {
return list.push({
name: parent.id ? parent.id.name : '[Anonymous]',
params: node.params,
range: node.range,
blockStart: node.body.range[0],
end: node.body.range[1]
});
} else if (typeof parent.length === 'number') {
return list.push({
name: parent.id ? parent.id.name : '[Anonymous]',
params: node.params,
range: node.range,
blockStart: node.body.range[0],
end: node.body.range[1]
});
} else if (typeof parent.key !== 'undefined') {
if (parent.key.type === 'Identifier') {
if (parent.value === node && parent.key.name) {
return list.push({
name: parent.key.name,
params: node.params,
range: node.range,
blockStart: node.body.range[0],
end: node.body.range[1]
});
}
}
}
}
});
return list;
};

exports.parse = function(code) {
var functions, tree;
tree = esprima.parse(code, {
loc: true,
range: true
});
functions = getFunctions(tree, code);

functions = functions.filter(function(fn) {
return fn.name !== '[Anonymous]';
});

return functions;
};

exports.interpret = function(code, tree) {
var functions;

functions = getFunctions(tree, code);

functions = functions.filter(function(fn) {
return fn.name !== '[Anonymous]';
});

return functions;
};
}).call(this);
5 changes: 4 additions & 1 deletion lib/panino/plugins/parsers/jsd_parser.js
Expand Up @@ -22,6 +22,7 @@ var util = require('util');
// 3rd-party
var _ = require('underscore');
var esprima = require('esprima');
var functionExtractor = require("function-extractor");

// internal
var Panino = require(__dirname + '/../../../panino');
Expand Down Expand Up @@ -53,7 +54,9 @@ var process_jsd = function(source, file, options, callback) {

// start parsing a la JSDuck
//try {
ast = esprima.parse(source, {comment: true, range: true, raw: true});
ast = esprima.parse(source, {comment: true, range: true, raw: true, loc: true});

//var functions = functionExtractor.interpret(source, ast);

docs = JSParser.parse(ast, source);

Expand Down
2 changes: 1 addition & 1 deletion lib/panino/renderers.js
@@ -1,5 +1,5 @@
'use strict';

// Simple "shared" renderers object.
// Used to avoid circular dependencies (between cli and panino).
// Used to avoid circular dependencies (between cli and Panino).
module.exports = {};
3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -33,7 +33,8 @@
"functional-docs": "",
"esprima": "",
"StringScanner": "",
"colors": ""
"colors": "",
"function-extractor": ""
},
"devDependencies" : { "jison": "~0.3.0" },

Expand Down

0 comments on commit 3cbba61

Please sign in to comment.