Skip to content

Commit

Permalink
Fixes private variables/functions being added, default values errors …
Browse files Browse the repository at this point in the history
…(thanks, Andres), multiple @returnn tags
  • Loading branch information
markwpearce committed Nov 16, 2020
1 parent 99f2b06 commit 6cab770
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 74 deletions.
146 changes: 95 additions & 51 deletions convert-brighterscript-docs.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ const path = require('path');

const jsCommentStartRegex = /^[\s]*(?:\/\*+)?[\s]*(.*)/g
const bsMeaningfulCommentRegex = /^[\s]*(?:'|REM)[\s]*\**[\s]*(.*)/g
const paramRegex = /@param (?:{([^}]*)} )?(\w+)[\s-\s|\s]*(.*)/
const returnRegex = /@returns?\s*(?:{(?:[^}]*)})?\s*(.*)/
const paramRegex = /@param\s+(?:{([^}]*)})?\s+(?:\[(\w+).*\]|(\w+))[\s-\s|\s]*(.*)/
const returnRegex = /@returns?\s*({(?:[^}]*)})?\s*(.*)/
const extendsRegex = /@extends/

/** @type {string[]} */
Expand Down Expand Up @@ -69,6 +69,27 @@ function getTypeName(type) {
return "dynamic"
}


/**
* Helper to clean up param or return description strings
*
* @param {string} [desc=""]
* @return {string} cleaned up string
*/
function paramOrReturnDescriptionHelper(desc = "") {
desc = (desc || "").trim()
if (desc.startsWith("-")) {
return desc;
}
if (desc.startsWith(",")) {
desc = desc.substring(1);
}
if (desc) {
return "- " + desc;
}
return ""
}

/**
* Finds the comment that ends the line above the given statement
*
Expand All @@ -83,11 +104,10 @@ function getCommentForStatement(comments, stmt) {
}

function getMemberOf(moduleName = "", namespaceName = "") {
if (namespaceName) {
return (" * @memberof module:" + namespaceName)
}
if (moduleName) {
return (` * @memberof module:${moduleName}`);
const memberOf = namespaceName || moduleName

if (memberOf) {
return (` * @memberof module:${memberOf}`);
}
return ""
}
Expand Down Expand Up @@ -167,78 +187,104 @@ function displayStatement(stmt) {
function processFunction(comment, func, moduleName = "", namespaceName = "") {
const output = []
let commentLines = convertCommentTextToJsDocLines(comment);
const paramNameList = []

// Find the param line in the comments that match each param
for (const param of func.func.parameters) {
let paramName = param.name.text;
paramNameList.push(paramName)
let paramType = getTypeName(param.type.kind);
let paramDescription;
for (var i = 0; i < commentLines.length; i++) {
let commentMatch = commentLines[i].match(paramRegex);
if (commentMatch && paramName === commentMatch[2]) {
if (commentMatch[1]) paramType = commentMatch[1];
paramDescription = commentMatch[3];
commentLines.splice(i, 1);
i--;
break;
let paramDescription = "";

// remove @param lines for the current param
commentLines = commentLines.filter(commentLine => {
let commentMatch = commentLine.match(paramRegex);
if (commentMatch) {

const commentParamName = (commentMatch[2] || commentMatch[3]) || ""
const commentParamType = commentMatch[1] || ""

if (paramName.trim().toLowerCase() === commentParamName.trim().toLowerCase()) {
// same parameter name - use these details
if (commentParamType) {
paramType = commentParamType.trim();
paramDescription = commentMatch[4] || paramDescription
}
return false
}
}
}
return true
})

let paramLine = ` * @param {${paramType}} `
if (param.defaultValue) {
let start = param.defaultValue.range.start;
let end = param.defaultValue.range.end;
let defaultValue = parserLines[start.line - 1].slice(start.character, end.character);
let defaultValue = parserLines[start.line].slice(start.character, end.character);
paramLine += `[${paramName}=${defaultValue}]`
} else {
paramLine += paramName;
}
if (paramDescription) paramLine += ` - ${paramDescription}`;
commentLines.push(paramLine);
else {

paramLine += paramName
}

if (paramDescription) {
paramLine += ` ${paramOrReturnDescriptionHelper(paramDescription)}`;
}
output.push(paramLine);
}
if (func.name.text[0] === '_' || func.accessModifier === "Private") {
commentLines.push(' * @access private');

if (func.name.text[0] === '_' || func.accessModifier?.kind === "Private") {
output.push(' * @access private');
}

let returnLine = ` * @return {${getTypeName(func.func.returns)}}`
// Find the return line in the comments
for (var i = 0; i < commentLines.length; i++) {
let commentMatch = commentLines[i].match(returnRegex);
if (commentMatch && commentMatch[1]) {
returnLine = ` * @return {${getTypeName(func.func.returns)}} - ${commentMatch[1]}`;

if (commentMatch) {
let commentReturnType = getTypeName(func.func.returns)
if (commentMatch[1] && commentMatch[1].trim().toLowerCase() == getTypeName(func.func.returns).toLowerCase) {
// there is a return type given, and it matches the type of the function
commentReturnType = commentMatch[1].trim()
}
returnLine = ` * @return {${commentReturnType}}`;
if (commentMatch[2]) {
returnLine += " " + paramOrReturnDescriptionHelper(commentMatch[2])
}
// remove the original comment @return line
commentLines.splice(i, 1);
break;
}
}

commentLines.push(returnLine);
commentLines.push(getMemberOf(moduleName, namespaceName));

const totalOutput = [...commentLines, ...output]
totalOutput.push(returnLine);
totalOutput.push(getMemberOf(moduleName, namespaceName));

if (func.overrides) {
commentLines.push(` * @override`);
totalOutput.push(` * @override`);
}

const funcName = func.name.text
let funcDeclaration = `function ${funcName}() {};\n`
let funcDeclaration = `function ${funcName} (${paramNameList.join(", ")}) { }; \n`
if (func instanceof bs.ClassMethodStatement) {
if (funcName.toLowerCase() === "new") {
commentLines.push(" * @constructor")
funcDeclaration = `constructor() {};\n`
totalOutput.push(" * @constructor")
funcDeclaration = `constructor(${paramNameList.join(", ")}) { }; \n`
}
else {
funcDeclaration = `${funcName}() {};\n`
funcDeclaration = `${funcName} (${paramNameList.join(", ")}) { }; \n`
}
}
commentLines.push(' */');
output.push(commentLines.join('\n'));
totalOutput.push(' */');

output.push(funcDeclaration);
totalOutput.push(funcDeclaration);
if (namespaceName) {
output.push(`${namespaceName}.${funcName} = ${funcName};`)
totalOutput.push(`${namespaceName}.${funcName} = ${funcName}; `)
}

return output.join('\n')
return totalOutput.join('\n')
}

/**
Expand All @@ -248,20 +294,17 @@ function processFunction(comment, func, moduleName = "", namespaceName = "") {
*
* @param {bs.CommentStatement} comment the comment in the line above this field
* @param {bs.ClassFieldStatement} field the field to process
* @returns {string} the property tag for the class this field is in
* @return {string} the property tag for the class this field is in
*/
function processClassField(comment, field) {
const output = []
if (field.accessModifier && field.accessModifier === "Private") {
if (field.accessModifier?.kind === "Private") {
return ""
}
let description = "";
if (comment) {
description = comment.text.replace(bsMeaningfulCommentRegex, '$1');
}
output.push(` * @property {${getTypeName(field.type)}} ${field.name.text} ${description}`)

return output.join('\n')
return ` * @property { ${getTypeName(field.type)} } ${field.name.text} ${description} `;
}


Expand All @@ -282,11 +325,10 @@ function processClass(comment, klass, moduleName = "", namespaceName = "") {
let commentLines = convertCommentTextToJsDocLines(comment);
const klassCode = groupStatements(klass.body)


let parentClassName = "", extendsLine = ""
if (klass.parentClassName) {
parentClassName = klass.parentClassName.getName()
extendsLine = ` * @extends ${klass.parentClassName.getName()}`
extendsLine = ` * @extends ${klass.parentClassName.getName()} `
}

for (var i = 0; i < commentLines.length; i++) {
Expand Down Expand Up @@ -324,7 +366,7 @@ function processClass(comment, klass, moduleName = "", namespaceName = "") {

output.push('}\n')
if (namespaceName) {
output.push(`${namespaceName}.${klassName} = ${klassName};`)
output.push(`${namespaceName}.${klassName} = ${klassName}; `)
}
return output.join('\n')
}
Expand Down Expand Up @@ -352,15 +394,15 @@ function processNamespace(comment, namespace, moduleName = "", parentNamespaceNa
let commentLines = convertCommentTextToJsDocLines(comment);

commentLines.push(getMemberOf(moduleName, parentNamespaceName));
commentLines.push(` * @namespace ${namespaceName}`)
commentLines.push(` * @namespace ${namespaceName} `)
commentLines.push(' */');

output.push(commentLines.join('\n'));
if (parentNamespaceName) {
output.push(`${parentNamespaceName}.namespaceName = {}`)
}
else {
output.push(`var ${namespaceName} = {};`);
output.push(`var ${namespaceName} = {}; `);
}
namespacesCreated.push(namespaceName)
}
Expand Down Expand Up @@ -432,6 +474,8 @@ exports.handlers = {
output.push(`/** @module ${moduleName} */`);
}
output.push(processStatements(statements, moduleName))

e.source = output.join('\n');
// console.log(e.source)
}
};
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@

' Namespace for testing
namespace TestBsDoc
namespace TestBsNamespace

' Test Brighterscript class
class TestBsKlass

' Public property
prop as float = 1

' I like eating pie
someField as float = 3.14
pi as float = 3.14

' Private properties should not have comments
private secret = "shhhhh!"

' Constructor
'@param {string} name for this Class
' @param {string} name for this Class
function new(name as string) as void
m.name = name
end function
Expand All @@ -27,5 +31,24 @@ namespace TestBsDoc
function sayHello() as string
return "hi " + m.name
end function


' Tells a secret
'
' @return {string}
private function tellASecret() as string
return "The secret is - " + m.secret
end function



' Tests a void return type with different capitalization
'
' @return {Void}
function doNothing() as void

end function


end class
end namespace
20 changes: 0 additions & 20 deletions examples/source/TestKlass.bs
Original file line number Diff line number Diff line change
@@ -1,23 +1,3 @@
' Test Brighterscript function
' @param {object} foo something
' @param {integer} bar another thing
' @return the word "brighterscript"
function testBsFunction(foo as object, bar as integer) as string
return "brighterscipt"
end function

' Give the maximum of two numbers
' @param {integer} x - the first number
' @param {integer} y - the second number
' @return {integer} the max of x and y
function max(x, y)
if x > y
return x
end if
return y
end function


namespace TestDoc

' Test a function inside a namespace function
Expand Down
46 changes: 46 additions & 0 deletions examples/source/bsFunctions.bs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
' Test Brighterscript function
' @param {object} foo something
' @param {integer} bar another thing
' @return the word "brighterscript"
function testBsFunction(foo as object, bar as integer) as string
return "brighterscipt"
end function

' Give the maximum of two numbers
' @param {integer} x - the first number
' @param {integer} y - the second number
' @return {integer} the max of x and y
function max(x, y)
if x > y
return x
end if
return y
end function


' Say a greeting to someone
'
' @param {string} personName - the name of the person to greet
' @param {string} [greeting="Hello"] - the greeting (try Hi, Goodbye, Bonjour, etc.)
' @return {string} - the complete greeting
function greetSomeone(personName as string, greeting = "Hello" as string) as string
return greeting + " " + personName
end function

' Always gives false
'
' @return {boolean}
function alwaysReturnFalse() as boolean
return false
end function


' This function causes problems for Andres
function andresError(param = True as boolean) as object
return {}
end function


sub subHasNoReturnValue()
? "Make sure it is nonempty"
end sub

0 comments on commit 6cab770

Please sign in to comment.