Skip to content

Commit 6cab770

Browse files
committed
Fixes private variables/functions being added, default values errors (thanks, Andres), multiple @returnn tags
1 parent 99f2b06 commit 6cab770

File tree

4 files changed

+167
-74
lines changed

4 files changed

+167
-74
lines changed

convert-brighterscript-docs.js

Lines changed: 95 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ const path = require('path');
44

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

1111
/** @type {string[]} */
@@ -69,6 +69,27 @@ function getTypeName(type) {
6969
return "dynamic"
7070
}
7171

72+
73+
/**
74+
* Helper to clean up param or return description strings
75+
*
76+
* @param {string} [desc=""]
77+
* @return {string} cleaned up string
78+
*/
79+
function paramOrReturnDescriptionHelper(desc = "") {
80+
desc = (desc || "").trim()
81+
if (desc.startsWith("-")) {
82+
return desc;
83+
}
84+
if (desc.startsWith(",")) {
85+
desc = desc.substring(1);
86+
}
87+
if (desc) {
88+
return "- " + desc;
89+
}
90+
return ""
91+
}
92+
7293
/**
7394
* Finds the comment that ends the line above the given statement
7495
*
@@ -83,11 +104,10 @@ function getCommentForStatement(comments, stmt) {
83104
}
84105

85106
function getMemberOf(moduleName = "", namespaceName = "") {
86-
if (namespaceName) {
87-
return (" * @memberof module:" + namespaceName)
88-
}
89-
if (moduleName) {
90-
return (` * @memberof module:${moduleName}`);
107+
const memberOf = namespaceName || moduleName
108+
109+
if (memberOf) {
110+
return (` * @memberof module:${memberOf}`);
91111
}
92112
return ""
93113
}
@@ -167,78 +187,104 @@ function displayStatement(stmt) {
167187
function processFunction(comment, func, moduleName = "", namespaceName = "") {
168188
const output = []
169189
let commentLines = convertCommentTextToJsDocLines(comment);
190+
const paramNameList = []
170191

171192
// Find the param line in the comments that match each param
172193
for (const param of func.func.parameters) {
173194
let paramName = param.name.text;
195+
paramNameList.push(paramName)
174196
let paramType = getTypeName(param.type.kind);
175-
let paramDescription;
176-
for (var i = 0; i < commentLines.length; i++) {
177-
let commentMatch = commentLines[i].match(paramRegex);
178-
if (commentMatch && paramName === commentMatch[2]) {
179-
if (commentMatch[1]) paramType = commentMatch[1];
180-
paramDescription = commentMatch[3];
181-
commentLines.splice(i, 1);
182-
i--;
183-
break;
197+
let paramDescription = "";
198+
199+
// remove @param lines for the current param
200+
commentLines = commentLines.filter(commentLine => {
201+
let commentMatch = commentLine.match(paramRegex);
202+
if (commentMatch) {
203+
204+
const commentParamName = (commentMatch[2] || commentMatch[3]) || ""
205+
const commentParamType = commentMatch[1] || ""
206+
207+
if (paramName.trim().toLowerCase() === commentParamName.trim().toLowerCase()) {
208+
// same parameter name - use these details
209+
if (commentParamType) {
210+
paramType = commentParamType.trim();
211+
paramDescription = commentMatch[4] || paramDescription
212+
}
213+
return false
214+
}
184215
}
185-
}
216+
return true
217+
})
186218

187219
let paramLine = ` * @param {${paramType}} `
188220
if (param.defaultValue) {
189221
let start = param.defaultValue.range.start;
190222
let end = param.defaultValue.range.end;
191-
let defaultValue = parserLines[start.line - 1].slice(start.character, end.character);
223+
let defaultValue = parserLines[start.line].slice(start.character, end.character);
192224
paramLine += `[${paramName}=${defaultValue}]`
193-
} else {
194-
paramLine += paramName;
195225
}
196-
if (paramDescription) paramLine += ` - ${paramDescription}`;
197-
commentLines.push(paramLine);
226+
else {
227+
228+
paramLine += paramName
229+
}
230+
231+
if (paramDescription) {
232+
paramLine += ` ${paramOrReturnDescriptionHelper(paramDescription)}`;
233+
}
234+
output.push(paramLine);
198235
}
199-
if (func.name.text[0] === '_' || func.accessModifier === "Private") {
200-
commentLines.push(' * @access private');
236+
237+
if (func.name.text[0] === '_' || func.accessModifier?.kind === "Private") {
238+
output.push(' * @access private');
201239
}
202240

203241
let returnLine = ` * @return {${getTypeName(func.func.returns)}}`
204242
// Find the return line in the comments
205243
for (var i = 0; i < commentLines.length; i++) {
206244
let commentMatch = commentLines[i].match(returnRegex);
207-
if (commentMatch && commentMatch[1]) {
208-
returnLine = ` * @return {${getTypeName(func.func.returns)}} - ${commentMatch[1]}`;
209-
245+
if (commentMatch) {
246+
let commentReturnType = getTypeName(func.func.returns)
247+
if (commentMatch[1] && commentMatch[1].trim().toLowerCase() == getTypeName(func.func.returns).toLowerCase) {
248+
// there is a return type given, and it matches the type of the function
249+
commentReturnType = commentMatch[1].trim()
250+
}
251+
returnLine = ` * @return {${commentReturnType}}`;
252+
if (commentMatch[2]) {
253+
returnLine += " " + paramOrReturnDescriptionHelper(commentMatch[2])
254+
}
255+
// remove the original comment @return line
210256
commentLines.splice(i, 1);
211-
break;
212257
}
213258
}
214259

215-
commentLines.push(returnLine);
216-
commentLines.push(getMemberOf(moduleName, namespaceName));
260+
261+
const totalOutput = [...commentLines, ...output]
262+
totalOutput.push(returnLine);
263+
totalOutput.push(getMemberOf(moduleName, namespaceName));
217264

218265
if (func.overrides) {
219-
commentLines.push(` * @override`);
266+
totalOutput.push(` * @override`);
220267
}
221268

222269
const funcName = func.name.text
223-
let funcDeclaration = `function ${funcName}() {};\n`
270+
let funcDeclaration = `function ${funcName} (${paramNameList.join(", ")}) { }; \n`
224271
if (func instanceof bs.ClassMethodStatement) {
225272
if (funcName.toLowerCase() === "new") {
226-
commentLines.push(" * @constructor")
227-
funcDeclaration = `constructor() {};\n`
273+
totalOutput.push(" * @constructor")
274+
funcDeclaration = `constructor(${paramNameList.join(", ")}) { }; \n`
228275
}
229276
else {
230-
funcDeclaration = `${funcName}() {};\n`
277+
funcDeclaration = `${funcName} (${paramNameList.join(", ")}) { }; \n`
231278
}
232279
}
233-
commentLines.push(' */');
234-
output.push(commentLines.join('\n'));
280+
totalOutput.push(' */');
235281

236-
output.push(funcDeclaration);
282+
totalOutput.push(funcDeclaration);
237283
if (namespaceName) {
238-
output.push(`${namespaceName}.${funcName} = ${funcName};`)
284+
totalOutput.push(`${namespaceName}.${funcName} = ${funcName}; `)
239285
}
240286

241-
return output.join('\n')
287+
return totalOutput.join('\n')
242288
}
243289

244290
/**
@@ -248,20 +294,17 @@ function processFunction(comment, func, moduleName = "", namespaceName = "") {
248294
*
249295
* @param {bs.CommentStatement} comment the comment in the line above this field
250296
* @param {bs.ClassFieldStatement} field the field to process
251-
* @returns {string} the property tag for the class this field is in
297+
* @return {string} the property tag for the class this field is in
252298
*/
253299
function processClassField(comment, field) {
254-
const output = []
255-
if (field.accessModifier && field.accessModifier === "Private") {
300+
if (field.accessModifier?.kind === "Private") {
256301
return ""
257302
}
258303
let description = "";
259304
if (comment) {
260305
description = comment.text.replace(bsMeaningfulCommentRegex, '$1');
261306
}
262-
output.push(` * @property {${getTypeName(field.type)}} ${field.name.text} ${description}`)
263-
264-
return output.join('\n')
307+
return ` * @property { ${getTypeName(field.type)} } ${field.name.text} ${description} `;
265308
}
266309

267310

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

285-
286328
let parentClassName = "", extendsLine = ""
287329
if (klass.parentClassName) {
288330
parentClassName = klass.parentClassName.getName()
289-
extendsLine = ` * @extends ${klass.parentClassName.getName()}`
331+
extendsLine = ` * @extends ${klass.parentClassName.getName()} `
290332
}
291333

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

325367
output.push('}\n')
326368
if (namespaceName) {
327-
output.push(`${namespaceName}.${klassName} = ${klassName};`)
369+
output.push(`${namespaceName}.${klassName} = ${klassName}; `)
328370
}
329371
return output.join('\n')
330372
}
@@ -352,15 +394,15 @@ function processNamespace(comment, namespace, moduleName = "", parentNamespaceNa
352394
let commentLines = convertCommentTextToJsDocLines(comment);
353395

354396
commentLines.push(getMemberOf(moduleName, parentNamespaceName));
355-
commentLines.push(` * @namespace ${namespaceName}`)
397+
commentLines.push(` * @namespace ${namespaceName} `)
356398
commentLines.push(' */');
357399

358400
output.push(commentLines.join('\n'));
359401
if (parentNamespaceName) {
360402
output.push(`${parentNamespaceName}.namespaceName = {}`)
361403
}
362404
else {
363-
output.push(`var ${namespaceName} = {};`);
405+
output.push(`var ${namespaceName} = {}; `);
364406
}
365407
namespacesCreated.push(namespaceName)
366408
}
@@ -432,6 +474,8 @@ exports.handlers = {
432474
output.push(`/** @module ${moduleName} */`);
433475
}
434476
output.push(processStatements(statements, moduleName))
477+
435478
e.source = output.join('\n');
479+
// console.log(e.source)
436480
}
437481
};

examples/source/TestBsDoc.bs renamed to examples/source/TestBsNamespace.bs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11

22
' Namespace for testing
3-
namespace TestBsDoc
3+
namespace TestBsNamespace
44

55
' Test Brighterscript class
66
class TestBsKlass
77

8+
' Public property
89
prop as float = 1
910

1011
' I like eating pie
11-
someField as float = 3.14
12+
pi as float = 3.14
13+
14+
' Private properties should not have comments
15+
private secret = "shhhhh!"
1216

1317
' Constructor
14-
'@param {string} name for this Class
18+
' @param {string} name for this Class
1519
function new(name as string) as void
1620
m.name = name
1721
end function
@@ -27,5 +31,24 @@ namespace TestBsDoc
2731
function sayHello() as string
2832
return "hi " + m.name
2933
end function
34+
35+
36+
' Tells a secret
37+
'
38+
' @return {string}
39+
private function tellASecret() as string
40+
return "The secret is - " + m.secret
41+
end function
42+
43+
44+
45+
' Tests a void return type with different capitalization
46+
'
47+
' @return {Void}
48+
function doNothing() as void
49+
50+
end function
51+
52+
3053
end class
3154
end namespace

examples/source/TestKlass.bs

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,3 @@
1-
' Test Brighterscript function
2-
' @param {object} foo something
3-
' @param {integer} bar another thing
4-
' @return the word "brighterscript"
5-
function testBsFunction(foo as object, bar as integer) as string
6-
return "brighterscipt"
7-
end function
8-
9-
' Give the maximum of two numbers
10-
' @param {integer} x - the first number
11-
' @param {integer} y - the second number
12-
' @return {integer} the max of x and y
13-
function max(x, y)
14-
if x > y
15-
return x
16-
end if
17-
return y
18-
end function
19-
20-
211
namespace TestDoc
222

233
' Test a function inside a namespace function

examples/source/bsFunctions.bs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
' Test Brighterscript function
2+
' @param {object} foo something
3+
' @param {integer} bar another thing
4+
' @return the word "brighterscript"
5+
function testBsFunction(foo as object, bar as integer) as string
6+
return "brighterscipt"
7+
end function
8+
9+
' Give the maximum of two numbers
10+
' @param {integer} x - the first number
11+
' @param {integer} y - the second number
12+
' @return {integer} the max of x and y
13+
function max(x, y)
14+
if x > y
15+
return x
16+
end if
17+
return y
18+
end function
19+
20+
21+
' Say a greeting to someone
22+
'
23+
' @param {string} personName - the name of the person to greet
24+
' @param {string} [greeting="Hello"] - the greeting (try Hi, Goodbye, Bonjour, etc.)
25+
' @return {string} - the complete greeting
26+
function greetSomeone(personName as string, greeting = "Hello" as string) as string
27+
return greeting + " " + personName
28+
end function
29+
30+
' Always gives false
31+
'
32+
' @return {boolean}
33+
function alwaysReturnFalse() as boolean
34+
return false
35+
end function
36+
37+
38+
' This function causes problems for Andres
39+
function andresError(param = True as boolean) as object
40+
return {}
41+
end function
42+
43+
44+
sub subHasNoReturnValue()
45+
? "Make sure it is nonempty"
46+
end sub

0 commit comments

Comments
 (0)