UNPKG

documon

Version:

A documentation system for mortals. Use with any language.

438 lines (319 loc) 13.4 kB
/* Part of Documon. Copyright (c) Michael Gieson. www.documon.net */ /* # ----------------- # run tests # ----------------- cd /Volumes/Drives/projects/documon/node_modules/documon/src/ node ./parseFlag.js var tests = [ // name after type "@foo {object | string} name - description is here", "@foo {object | string} name.kid - description is here", "@foo {object | string} name.kid - description is here", "@foo {object | string} name=\"bar\" - description with {other} bracket @with at sign here", "@foo {object | string} name = \"bar\" - description with {other} bracket @with at sign here", "@foo {object | string} name = \"bar\" - description with {other} bracket @with at sign here", "@foo {object | string} name = \"bar\"", "@foo {object | string} name", "@foo {object | string}", "@foo {object} name - description is here", // name - desc "@foo {object} name - description is here", // } tab space name - desc "@foo {object} name - description is here", // } space tab name - desc "@foo {} name - description is here", // name - desc "@foo {object} name - description is here", // name - desc "@foo {object} name - description is here", // name space tab(s) - desc "@foo {object} name description is here", // name tab(s) desc "@foo {object} name description is here", // name space tab desc "@foo {object} name description is here", // name space tab space desc "@foo {object} description is here", "@foo {object} - description is here", "@foo {object} description", "@foo object=\"val\"", "@foo object description is here", "@foo object - description is here", "@foo description is here", "@foo - description is here", "@foo", "@foo ", "@foo ", // name before type "@foo name {object | string} - description is here", "@foo name.kid {object | string} - description is here", "@foo name.kid {object | string} - description is here", "@foo name=\"bar\" {object | string} - description with {other} bracket @with at sign here", "@foo name = \"bar\" {object | string} - description with {other} bracket @with at sign here", "@foo name = \"bar\" {object | string} - description with {other} bracket @with at sign here", "@foo name = \"bar\" {object | string} ", "@foo name {object | string} ", "@foo {object | string}", "@foo name {object} - description is here", // name - desc "@foo name {object} - description is here", // } tab space name - desc "@foo name {object} - description is here", // } space tab name - desc "@foo name {} - description is here", // name - desc "@foo name {object} - description is here", // name - desc "@foo name {object} - description is here", // name space tab(s) - desc "@foo name{object} description is here", // name tab(s) desc "@foo name {object} description is here", // name space tab desc "@foo name {object} description is here", // name space tab space desc "@foo {object} description is here", "@foo {object} - description is here", "@foo {object} description", "@foo object=\"val\"", "@foo object description is here", "@foo object - description is here", "@foo description is here", "@foo - description is here", "@foo", "@foo ", "@foo ", ]; var output = { flags: [] } for (var i = 0; i < tests.length; i++) { var obj = {}; var line = tests[i]; parseFlag(line, output.flags); } function testResults(obj, tab) { tab = tab || ""; for (var i = 0; i < obj.length; i++) { var item = obj[i]; con sole.log(tab + "-----------------------------------"); for (var prop in item) { var addTab = ""; if (prop.length < 6) { addTab = "\t"; } cons ole.log(tab + prop + " : \t" + addTab + item[prop]); if (prop == "children") { testResults(item[prop], "\t") } } } } testResults(output.flags) */ // ---------------------------------------------------------------------------------------------------------- // ---------------------------------------------- Docs ------------------------------------------------------------ // ---------------------------------------------------------------------------------------------------------- /** Fills the output object with the following properties (if they exist) object { source // Entire first line inlcuding the @flag (only first line) after // Everything after the @flag name // One word following {type}. Or first word after the @flag definition when no {type}. children // name.kid - Array of children parent // if am a child, this is my parent. flag // @flag token with @ stripped defaultVal // name=val afterType // first line after text // } Here's an expanded and exmple'd definition list source : The entire comment block after : Everything after the @flag token "as is" (kinda like source) - __source__ : The entire comment block - __after__ : Everything after the @flag token "as is" (kinda like source) e.g. in this line: @foo {type} name descr after yields: {type} name descr - __name__ : The first word following the {type} definition. Or the first word after the @flag definition - __children__ : If a name is written as foo.bar then foo is the parent and bar is a child. Future processing fills the array forming a heirarchy. - __parent__ : The parent flag of a child. This property only exists on children flags. - __defaultVal__ : When name=foo then default value will be foo. Note that quotes are stripped. e.g. foo="bar" sets default property to "bar" (without the quotes) and name property to "foo". - __flag__ : The flag kind - the @ is stripped - __afterType__ : Everything after the {type} definition e.g. @flag {type} name - descr ... yields: name - descr - __text__ : The description for the paramter. Note that additional description text can be provided below the @flag. e.g. @flag {type} name - description more description below the flag here @flag {kind} name.child=defaultVal - description \n stuff on next line \n and other next lines... |flag| |defaultVal| |child| |parent| |name| |text ------------------------------------------------------| |afterType ---------------------------| |after -------------------------------------| |source ------------------------------------------| @class parseFlags @package documon */ /* */ var re_optional = /[\[\]]/g; function processName(name, obj, output) { var parent; // -------------- // MUST BE FIRST - because the default value may contain a bracket or dot! // -------------- // Look for defautl value: name=1 or name="1" and strip quotes // e.g. if (name.indexOf("=") > -1) { var Aname = name.split("="); name = Aname.shift(); //obj.defaultVal = Aname.join("=").trim().replace(/^["'](.*)["']$/g, '$1'); // strip surrounding quotes obj.defaultVal = Aname.join("=").trim().replace(/("|'|\[|\])/g, ''); // strip quotes and brackets } // See if optional var hasBrackets = name.match(re_optional); if (hasBrackets) { obj.optional = true; name = name.replace(/[\[\]]/g, ""); } // Look for sub.property if (name.indexOf(".") > -1) { // Allow REST notation for args... if(name.indexOf("...") < 0){ // TODO: probably want to allow many more depths. For now, just one will do. var Aname = name.split("."); parent = Aname.shift(); obj.parent = parent; name = Aname.join("."); } } obj.name = name; if (parent) { for (var i = 0; i < output.length; i++) { var item = output[i]; if (item.name === parent) { if (!item.children) { item.children = []; } return item.children; // the object to put the flag into } } } return output; } function parseFlag(line, output) { line = line.trim(); var source = line; var obj = { source: line }; // ------------- // flag var flag = line.match(/^@(.*?)(?:\s|$)/)[1]; obj.flag = flag; // chop @foo line = line.replace(/^@.*?(?:\s|$)/, "").trim(); obj.after = line; // after flag if (line) { // parse name before type // e.g. @foo name {type} descr var frontName = line.match(/^(.*?)(?:\{)/); if (frontName) { if (frontName[1]) { frontName = frontName[1].trim(); frontName = frontName.replace(/[\s].*?(=).*?(?=[\S])/, "$1"); line = line.replace(/^(.*?)(?=\{)/, "").trim(); } else { frontName = null; } } // ------------- // type // TODO also allow type to be defined in square-brackets e.g. @foo [type] name - descr if (line.charAt(0) == "{") { var types = line.match(/^\{(.*?)\}/); if (types && types.length) { obj.type = types[1]; } // chop {object} line = line.replace(/^\{.*?\}/, "").trim(); } // after type if (line) { // ------------ // name // var Aline = line.split(/\s/); var name = Aline[0].trim(); // Useful for things like @returns {object} - description var afterType = line; if (afterType.charAt(0) == "-") { afterType = afterType.substr(1).trim(); } obj.afterType = afterType; var skipName = false; if (line.charAt(0) != "-") { if (frontName && ! Aline.length) { output = processName(frontName, obj, output); obj.single = true; // When only a single word at the front of the line. } else if (Aline.length === 1) { // Altering output if this is a child (processName puts this flag into the parent'd children array) output = processName(name, obj, output); // flag a single word, since some things don't have a "name", and may have: // - a single word description // - a {type} definition without brackets. // - obj.single = true; // after name } else { if (frontName) { output = processName(frontName, obj, output); } else { // grab first word and assume it's the name var first = line.match(/^(.*?)(?:\s|$)/)[1]; output = processName(first, obj, output); // store everything after the // lop'd off the first word line = line.replace(/^(.*?)(?:\s|$)/, "").trim(); // Look for and equal sign that was seperated from the name: // name = "foo" if (line.charAt(0) == "=") { // I'm not smart enough to regex the space between "=" and "foo": // = "foo" description here // // So just chop off the = sign line = line.substring(1).trim(); // ... and grab the first word, which is the value. (same "var first..." above) var val = line.match(/^(.*?)(?:\s|$)/)[1]; if (val) { // ... then glue things back together as they "should be" (name="foo") name = name + "=" + val; output = processName(name, obj, output); // extract the "val" from the line line = line.replace(/^(.*?)(?:\s|$)/, "").trim(); } } } } } else { if (frontName) { output = processName(frontName, obj, output); } } // description if (line) { if (line.charAt(0) == "-") { line = line.substring(1).trim(); } obj.text = line; } } else { if (frontName) { output = processName(frontName, obj, output); } } } output.push(obj); return obj; } module.exports = parseFlag;