/******************************************************************************
 * Copyright 2021 TypeFox GmbH
 * This program and the accompanying materials are made available under the
 * terms of the MIT License, which is available in the project root.
 ******************************************************************************/ import { findAssignment } from '../grammar/grammar-util' ; import { AstNode } from '../syntax-tree' ; import { LangiumDocument } from './documents' ; export interface AstNodeLocator { param node returns see AstNodeLocator . getAstNode getAstNodePath ( node ) : string ; param document param path returns see AstNodeLocator . getAstNodePath getAstNode ( document , path ) : AstNode | undefined ; } export class DefaultAstNodeLocator implements AstNodeLocator { protected segmentSeparator = '/' ; protected indexSeparator = '@' ; getAstNodePath ( node ) { if ( node . $path ) { return node . $path ; } if ( node . $container ) { const containerPath = this . getAstNodePath ( node . $container ) ; const newSegment = this . getPathSegment ( node , node . $container ) ; const nodePath = containerPath + this . segmentSeparator + newSegment ; node . $path = nodePath ; return nodePath ; } return '' ; } protected getPathSegment ( node , container ) { if ( node . $cstNode ) { const assignment = findAssignment ( node . $cstNode ) ; if ( assignment ) { if ( assignment . operator === '+=' ) { const array = ( container as unknown as Record < string , AstNode [ ] > ) [ assignment . feature ] ; const idx = array . indexOf ( node ) ; return assignment . feature + this . indexSeparator + idx ; } return assignment . feature ; } } return '<missing>' ; } getAstNode ( document , path ) { const segments = path . split ( this . segmentSeparator ) ; return segments . reduce ( ( previousValue , currentValue ) => { if ( ! previousValue || currentValue . length === 0 ) { return previousValue ; } const propertyIndex = currentValue . indexOf ( this . indexSeparator ) ; if ( propertyIndex > 0 ) { const property = currentValue . substring ( 0 , propertyIndex ) ; const arrayIndex = parseInt ( currentValue . substring ( propertyIndex + 1 ) ) ; const array = ( previousValue as unknown as Record < string , AstNode [ ] > ) [ property ] ; return array [ arrayIndex ] ; } return ( previousValue as unknown as Record < string , AstNode > ) [ currentValue ] ; } , document . parseResult . value ) ; } }