@@ -386,20 +386,29 @@ export function findNodeAtOffset(node: Node, offset: number, includeRightBound =
386386export function visit ( text : string , visitor : JSONVisitor , options : ParseOptions = ParseOptions . DEFAULT ) : any {
387387
388388 const _scanner = createScanner ( text , false ) ;
389+ // Important: Only pass copies of this to visitor functions to prevent accidental modification, and
390+ // to not affect visitor functions which stored a reference to a previous JSONPath
391+ const _jsonPath : JSONPath = [ ] ;
389392
390393 function toNoArgVisit ( visitFunction ?: ( offset : number , length : number , startLine : number , startCharacter : number ) => void ) : ( ) => void {
391394 return visitFunction ? ( ) => visitFunction ( _scanner . getTokenOffset ( ) , _scanner . getTokenLength ( ) , _scanner . getTokenStartLine ( ) , _scanner . getTokenStartCharacter ( ) ) : ( ) => true ;
392395 }
396+ function toNoArgVisitWithPath ( visitFunction ?: ( offset : number , length : number , startLine : number , startCharacter : number , pathSupplier : ( ) => JSONPath ) => void ) : ( ) => void {
397+ return visitFunction ? ( ) => visitFunction ( _scanner . getTokenOffset ( ) , _scanner . getTokenLength ( ) , _scanner . getTokenStartLine ( ) , _scanner . getTokenStartCharacter ( ) , ( ) => _jsonPath . slice ( ) ) : ( ) => true ;
398+ }
393399 function toOneArgVisit < T > ( visitFunction ?: ( arg : T , offset : number , length : number , startLine : number , startCharacter : number ) => void ) : ( arg : T ) => void {
394400 return visitFunction ? ( arg : T ) => visitFunction ( arg , _scanner . getTokenOffset ( ) , _scanner . getTokenLength ( ) , _scanner . getTokenStartLine ( ) , _scanner . getTokenStartCharacter ( ) ) : ( ) => true ;
395401 }
402+ function toOneArgVisitWithPath < T > ( visitFunction ?: ( arg : T , offset : number , length : number , startLine : number , startCharacter : number , pathSupplier : ( ) => JSONPath ) => void ) : ( arg : T ) => void {
403+ return visitFunction ? ( arg : T ) => visitFunction ( arg , _scanner . getTokenOffset ( ) , _scanner . getTokenLength ( ) , _scanner . getTokenStartLine ( ) , _scanner . getTokenStartCharacter ( ) , ( ) => _jsonPath . slice ( ) ) : ( ) => true ;
404+ }
396405
397- const onObjectBegin = toNoArgVisit ( visitor . onObjectBegin ) ,
398- onObjectProperty = toOneArgVisit ( visitor . onObjectProperty ) ,
406+ const onObjectBegin = toNoArgVisitWithPath ( visitor . onObjectBegin ) ,
407+ onObjectProperty = toOneArgVisitWithPath ( visitor . onObjectProperty ) ,
399408 onObjectEnd = toNoArgVisit ( visitor . onObjectEnd ) ,
400- onArrayBegin = toNoArgVisit ( visitor . onArrayBegin ) ,
409+ onArrayBegin = toNoArgVisitWithPath ( visitor . onArrayBegin ) ,
401410 onArrayEnd = toNoArgVisit ( visitor . onArrayEnd ) ,
402- onLiteralValue = toOneArgVisit ( visitor . onLiteralValue ) ,
411+ onLiteralValue = toOneArgVisitWithPath ( visitor . onLiteralValue ) ,
403412 onSeparator = toOneArgVisit ( visitor . onSeparator ) ,
404413 onComment = toNoArgVisit ( visitor . onComment ) ,
405414 onError = toOneArgVisit ( visitor . onError ) ;
@@ -474,6 +483,8 @@ export function visit(text: string, visitor: JSONVisitor, options: ParseOptions
474483 onLiteralValue ( value ) ;
475484 } else {
476485 onObjectProperty ( value ) ;
486+ // add property name afterwards
487+ _jsonPath . push ( value ) ;
477488 }
478489 scanNext ( ) ;
479490 return true ;
@@ -524,6 +535,7 @@ export function visit(text: string, visitor: JSONVisitor, options: ParseOptions
524535 } else {
525536 handleError ( ParseErrorCode . ColonExpected , [ ] , [ SyntaxKind . CloseBraceToken , SyntaxKind . CommaToken ] ) ;
526537 }
538+ _jsonPath . pop ( ) ; // remove processed property name
527539 return true ;
528540 }
529541
@@ -562,6 +574,7 @@ export function visit(text: string, visitor: JSONVisitor, options: ParseOptions
562574 function parseArray ( ) : boolean {
563575 onArrayBegin ( ) ;
564576 scanNext ( ) ; // consume open bracket
577+ let isFirstElement = true ;
565578
566579 let needsComma = false ;
567580 while ( _scanner . getToken ( ) !== SyntaxKind . CloseBracketToken && _scanner . getToken ( ) !== SyntaxKind . EOF ) {
@@ -577,12 +590,21 @@ export function visit(text: string, visitor: JSONVisitor, options: ParseOptions
577590 } else if ( needsComma ) {
578591 handleError ( ParseErrorCode . CommaExpected , [ ] , [ ] ) ;
579592 }
593+ if ( isFirstElement ) {
594+ _jsonPath . push ( 0 ) ;
595+ isFirstElement = false ;
596+ } else {
597+ ( _jsonPath [ _jsonPath . length - 1 ] as number ) ++ ;
598+ }
580599 if ( ! parseValue ( ) ) {
581600 handleError ( ParseErrorCode . ValueExpected , [ ] , [ SyntaxKind . CloseBracketToken , SyntaxKind . CommaToken ] ) ;
582601 }
583602 needsComma = true ;
584603 }
585604 onArrayEnd ( ) ;
605+ if ( ! isFirstElement ) {
606+ _jsonPath . pop ( ) ; // remove array index
607+ }
586608 if ( _scanner . getToken ( ) !== SyntaxKind . CloseBracketToken ) {
587609 handleError ( ParseErrorCode . CloseBracketExpected , [ SyntaxKind . CloseBracketToken ] , [ ] ) ;
588610 } else {
0 commit comments