@@ -204,6 +204,8 @@ export function createLocalOrExportedOrGlobalDeclaration(
204204 }
205205 }
206206
207+ setJSDocComments ( context , tsOriginal , declaration , assignment ) ;
208+
207209 if ( declaration && assignment ) {
208210 return [ declaration , assignment ] ;
209211 } else if ( declaration ) {
@@ -215,6 +217,103 @@ export function createLocalOrExportedOrGlobalDeclaration(
215217 }
216218}
217219
220+ /**
221+ * Apply JSDoc comments to the newly-created Lua statement, if present.
222+ * https://stackoverflow.com/questions/47429792/is-it-possible-to-get-comments-as-nodes-in-the-ast-using-the-typescript-compiler
223+ */
224+ function setJSDocComments (
225+ context : TransformationContext ,
226+ tsOriginal : ts . Node | undefined ,
227+ declaration : lua . VariableDeclarationStatement | undefined ,
228+ assignment : lua . AssignmentStatement | undefined
229+ ) {
230+ // Respect the vanilla TypeScript option of "removeComments":
231+ // https://www.typescriptlang.org/tsconfig#removeComments
232+ if ( context . options . removeComments ) {
233+ return ;
234+ }
235+
236+ const docCommentArray = getJSDocCommentFromTSNode ( context , tsOriginal ) ;
237+ if ( docCommentArray === undefined ) {
238+ return ;
239+ }
240+
241+ if ( declaration && assignment ) {
242+ declaration . leadingComments = docCommentArray ;
243+ } else if ( declaration ) {
244+ declaration . leadingComments = docCommentArray ;
245+ } else if ( assignment ) {
246+ assignment . leadingComments = docCommentArray ;
247+ }
248+ }
249+
250+ function getJSDocCommentFromTSNode (
251+ context : TransformationContext ,
252+ tsOriginal : ts . Node | undefined
253+ ) : string [ ] | undefined {
254+ if ( tsOriginal === undefined ) {
255+ return undefined ;
256+ }
257+
258+ // The "name" property is only on a subset of node types; we want to be permissive and get the
259+ // comments from as many nodes as possible.
260+ const node = tsOriginal as any ;
261+ if ( node . name === undefined ) {
262+ return undefined ;
263+ }
264+
265+ const symbol = context . checker . getSymbolAtLocation ( node . name ) ;
266+ if ( symbol === undefined ) {
267+ return undefined ;
268+ }
269+
270+ // The TypeScript compiler separates JSDoc comments into the "documentation comment" and the
271+ // "tags". The former is conventionally at the top of the comment, and the bottom is
272+ // conventionally at the bottom. We need to get both from the TypeScript API and then combine
273+ // them into one block of text.
274+ const docCommentArray = symbol . getDocumentationComment ( context . checker ) ;
275+ const docCommentText = ts . displayPartsToString ( docCommentArray ) . trim ( ) ;
276+
277+ const jsDocTagInfoArray = symbol . getJsDocTags ( context . checker ) ;
278+ const jsDocTagsTextLines = jsDocTagInfoArray . map ( jsDocTagInfo => {
279+ let text = "@" + jsDocTagInfo . name ;
280+ if ( jsDocTagInfo . text !== undefined ) {
281+ const tagDescriptionTextArray = jsDocTagInfo . text
282+ . filter ( symbolDisplayPart => symbolDisplayPart . text . trim ( ) !== "" )
283+ . map ( symbolDisplayPart => symbolDisplayPart . text . trim ( ) ) ;
284+ const tagDescriptionText = tagDescriptionTextArray . join ( " " ) ;
285+ text += " " + tagDescriptionText ;
286+ }
287+ return text ;
288+ } ) ;
289+ const jsDocTagsText = jsDocTagsTextLines . join ( "\n" ) ;
290+
291+ const combined = ( docCommentText + "\n\n" + jsDocTagsText ) . trim ( ) ;
292+ if ( combined === "" ) {
293+ return undefined ;
294+ }
295+
296+ // By default, TSTL will display comments immediately next to the "--" characters. We can make
297+ // the comments look better if we separate them by a space (similar to what Prettier does in
298+ // JavaScript/TypeScript).
299+ const linesWithoutSpace = combined . split ( "\n" ) ;
300+ const lines = linesWithoutSpace . map ( line => ` ${ line } ` ) ;
301+
302+ // We want to JSDoc comments to map on to LDoc comments:
303+ // https://stevedonovan.github.io/ldoc/manual/doc.md.html
304+ // LDoc comments require that the first line starts with three hyphens.
305+ // Thus, need to add a hyphen to the first line.
306+ const firstLine = lines [ 0 ] ;
307+ if ( firstLine . startsWith ( " @" ) ) {
308+ lines . unshift ( "-" ) ;
309+ } else {
310+ lines . shift ( ) ;
311+ lines . unshift ( "-" + firstLine ) ;
312+ }
313+
314+ return lines ;
315+ }
316+
218317export const createNaN = ( tsOriginal ?: ts . Node ) =>
219318 lua . createBinaryExpression (
220319 lua . createNumericLiteral ( 0 ) ,
0 commit comments