Skip to content

Instantly share code, notes, and snippets.

@DmitrySoshnikov
Created September 1, 2011 18:22
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DmitrySoshnikov/1186853 to your computer and use it in GitHub Desktop.
Save DmitrySoshnikov/1186853 to your computer and use it in GitHub Desktop.
Runtime documentation for function declarations
/**
* Simple doc-property generator. Uses JavaDoc style comments.
* Also provides type checking guards.
*
* Dependencies: SpiderMonkey >= 1.7
*
* by Dmitry Soshnikov <dmitry.soshnikov@gmail.com>
* MIT Style License
*/
/**
* include
* @param {String} filename -- file to load and pre-process
*
* Loads source file and processes it with
* forming __doc__ property of function declarations.
* Also provides type checking guards. Finally, "eval"s
* the source in the global context.
*
* TODO:
* - support FE (including anonymous)
* - better regexp to consider more cases
*/
function include(filename) {
// get the source as a string
var source = snarf(filename);
var re = /(\/\*[^/]*\*\/)\s*(function\s*(\w*)\s*\([^)]+\)\s*{)?/;
var globalRe = RegExp(re.source, "g");
var singleRe = RegExp(re.source);
source = source.replace(globalRe, function(data) {
// separate doc-string, function name and header
var [_, comment, header, name] = data.match(singleRe);
// since function declarations are created on
// entering the context, we may place __doc__ generation
// before the function definiton itself (thus, we don't need to
// find the closing } in the regexp, but only function header
var transformedCode = name + ".__doc__ = " + '"' + comment.replace(/\n/g, "\\n") + '";';
// validation code
var paramsRe = /@param {(\w+)} (\w+)/g;
var validationCode = [];
var param;
while (param = paramsRe.exec(comment)) {
var paramType = param[1].toLowerCase();
var paramName = param[2];
// build simple validation if (typeof name != type) throw TypeError(...)
validationCode.push(
'if (typeof ' + paramName + ' != "' + paramType + '") ' +
'throw TypeError(\'"' + paramName + '" must be a ' + paramType + '\');'
);
}
return transformedCode + header + validationCode.join("");
});
("global", eval)(source);
}
/**
* help
* @param {Function} fn
* Prints help on a function
*/
function help(fn) {
print('Help on "' + fn.name + '" function:\n');
print(fn.__doc__);
}
/**
* sum
* @param {Number} x
* @param {Number} y
* The function of summation.
*/
function sum(x, y) {
return x + y;
}
/**
* multSum
* @param {Number} x
* @param {Number} y
* @param {String} value
* The function of calculation.
*/
function calculate(x, y, value) {
// comment
print(value + ": " + sum(x, y));
}
// load our library
load("doc.js");
// and the test source
include("source.js");
// ---------- Test documentation ----------
help(sum);
// Result:
// Help on "sum" function:
//
// /**
// * sum
// * @param {Number} x
// * @param {Number} y
// * The function of summation.
// */
help(calculate);
// Result:
// Help on "calculate" function:
//
// /**
// * multSum
// * @param {Number} x
// * @param {Number} y
// * @param {String} value
// * The function of calculation.
// */
// ---------- Test guards ----------
sum(1, 2); // 3, OK
calculate(1, 2, "value"); // value: 3
sum(1, "2"); // TypeError: "y" must be a number
calculate(1, 2, 4); // TypeError: "value" must be a string
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment