11const doctrine = require ( 'doctrine' ) ;
22const JSDocTokenizer = require ( './jsdoc-tokenizer' ) ;
33
4- const JSDocTypeTokenizer = new JSDocTokenizer ( {
5- type : true ,
6- range : true
7- } ) ;
4+ const JSDocTokenizers = {
5+ default : new JSDocTokenizer ( {
6+ range : true
7+ } ) ,
8+ type : new JSDocTokenizer ( {
9+ type : true ,
10+ range : true
11+ } )
12+ } ;
813
914/**
1015 * @param {ASTNode } node
@@ -282,7 +287,8 @@ function parseJSDoc(comment) {
282287 return null ;
283288 }
284289
285- const content = doctrine . unwrapComment ( comment . value ) ;
290+ const content = doctrine . unwrapComment ( comment . value )
291+ . replace ( / ^ \s * / , '' ) ; // Remove heading whitespace
286292
287293 let JSDoc = null ;
288294 try {
@@ -373,7 +379,7 @@ function getJSDocTypeContent(JSDoc, type) {
373379 * @return {Array<JSDocTokenWithRange> }
374380 */
375381function getJSDocTagTokens ( JSDoc , tag ) {
376- return JSDocTypeTokenizer . tokenize ( JSDoc . content . slice ( ...tag . range ) )
382+ return JSDocTokenizers . default . tokenize ( JSDoc . content . slice ( ...tag . range ) )
377383 . map ( ( token ) => {
378384 token . range [ 0 ] += tag . range [ 0 ] ;
379385 token . range [ 1 ] += tag . range [ 0 ] ;
@@ -388,7 +394,7 @@ function getJSDocTagTokens(JSDoc, tag) {
388394 * @return {Array<JSDocTokenWithRange> }
389395 */
390396function getJSDocTypeTokens ( JSDoc , type ) {
391- return JSDocTypeTokenizer . tokenize ( JSDoc . content . slice ( ...type . range ) )
397+ return JSDocTokenizers . type . tokenize ( JSDoc . content . slice ( ...type . range ) )
392398 . map ( ( token ) => {
393399 token . range [ 0 ] += type . range [ 0 ] ;
394400 token . range [ 1 ] += type . range [ 0 ] ;
@@ -427,6 +433,53 @@ function getJSDocTokenAfter(tokens, targetToken) {
427433 return tokens . find ( ( token ) => token . range [ 0 ] === targetToken . range [ 1 ] ) || null ;
428434}
429435
436+ /**
437+ * @param {Array<JSDocTokenWithRange> } tokens
438+ * @param {JSDocTokenWithRange } tokenA
439+ * @param {JSDocTokenWithRange } tokenB
440+ * @return {Array<JSDocTokenWithRange> }
441+ */
442+ function getJSDocTokensBetween ( tokens , tokenA , tokenB ) {
443+ const tokensBetween = [ ] ;
444+
445+ let cursor = tokenA ;
446+ while ( cursor ) {
447+ cursor = getJSDocTokenAfter ( tokens , cursor ) ;
448+
449+ if ( ! cursor || cursor . range [ 0 ] === tokenB . range [ 0 ] ) {
450+ break ;
451+ }
452+
453+ tokensBetween . push ( cursor ) ;
454+ }
455+
456+ return tokensBetween ;
457+ }
458+
459+ /**
460+ * @param {Array<JSDocTokenWithRange> } tokens
461+ * @param {{
462+ * type: (string|undefined),
463+ * value: (string|undefined)
464+ * }= } options
465+ * @return {?JSDocTokenWithRange }
466+ */
467+ function findFirstJSDocToken ( tokens , { type, value} ) {
468+ return tokens . find ( ( token ) => ( ! type || token . type === type ) && ( ! value || token . value === value ) ) || null ;
469+ }
470+
471+ /**
472+ * @param {Array<JSDocTokenWithRange> } tokens
473+ * @param {{
474+ * type: (string|undefined),
475+ * value: (string|undefined)
476+ * }= } options
477+ * @return {?JSDocTokenWithRange }
478+ */
479+ function findLastJSDocToken ( tokens , { type, value} ) {
480+ return findFirstJSDocToken ( tokens . slice ( ) . reverse ( ) , { type, value} ) ;
481+ }
482+
430483/**
431484 * @param {Array<JSDocTokenWithRange> } tokens
432485 * @param {JSDocTokenWithRange } token
@@ -438,26 +491,22 @@ function getJSDocTokenAfter(tokens, targetToken) {
438491 * @return {?JSDocTokenWithRange }
439492 */
440493function findNonWhitespaceSiblingJSDocToken ( tokens , token , { type, value, moveForward = true } = { } ) {
441- let currentToken = token ;
442-
443- while ( currentToken ) {
444- currentToken = moveForward ?
445- getJSDocTokenAfter ( tokens , currentToken ) :
446- getJSDocTokenBefore ( tokens , currentToken ) ;
494+ let cursor = token ;
495+ while ( cursor ) {
496+ cursor = moveForward ?
497+ getJSDocTokenAfter ( tokens , cursor ) :
498+ getJSDocTokenBefore ( tokens , cursor ) ;
447499
448- if ( ! currentToken ) {
500+ if ( ! cursor ) {
449501 return null ;
450502 }
451503
452- if ( currentToken . type === 'Whitespace' ) {
504+ if ( cursor . type === 'Whitespace' ) {
453505 continue ;
454506 }
455507
456- if (
457- ( ! type || currentToken . type === type ) &&
458- ( ! value || currentToken . value === value )
459- ) {
460- return currentToken ;
508+ if ( ( ! type || cursor . type === type ) && ( ! value || cursor . value === value ) ) {
509+ return cursor ;
461510 }
462511
463512 return null ;
@@ -589,8 +638,11 @@ module.exports = {
589638 getJSDocSubtypeTokens,
590639 getJSDocTokenBefore,
591640 getJSDocTokenAfter,
641+ getJSDocTokensBetween,
592642 getScopeFromJSDoc,
593643 getStaticTypeFromJSDoc,
644+ findFirstJSDocToken,
645+ findLastJSDocToken,
594646 findNonWhitespaceSiblingJSDocToken,
595647 traverseJSDocType
596648} ;
0 commit comments