import { Node , isScalar , Scalar , isMap , YAMLMap , isPair , Pair , isSeq , YAMLSeq , isNode , isAlias , Alias , Document , LineCounter , } from 'yaml' ; import { ASTNode } from '../jsonASTTypes' ; import { NullASTNodeImpl , PropertyASTNodeImpl , StringASTNodeImpl , ObjectASTNodeImpl , NumberASTNodeImpl , ArrayASTNodeImpl , BooleanASTNodeImpl , } from './jsonParser07' ; type NodeRange = [ number , number , number ] ; const maxRefCount = 1000 ; let refDepth = 0 ; export function convertAST ( parent , node , doc , lineCounter ) { if ( ! parent ) { refDepth = 0 ; } if ( ! node ) { return ; } if ( isMap ( node ) ) { return convertMap ( node , parent , doc , lineCounter ) ; } if ( isPair ( node ) ) { return convertPair ( node , parent , doc , lineCounter ) ; } if ( isSeq ( node ) ) { return convertSeq ( node , parent , doc , lineCounter ) ; } if ( isScalar ( node ) ) { return convertScalar ( node , parent ) ; } if ( isAlias ( node ) ) { if ( refDepth > maxRefCount ) { return ; } return convertAlias ( node , parent , doc , lineCounter ) ; } } function convertMap ( node , parent , doc , lineCounter ) { let range ; if ( node . flow && ! node . range ) { range = collectFlowMapRange ( node ) ; } else { range = node . range ; } const result = new ObjectASTNodeImpl ( parent , node , ... toFixedOffsetLength ( range , lineCounter ) ) ; for ( const it of node . items ) { if ( isPair ( it ) ) { result . properties . push ( < PropertyASTNodeImpl > convertAST ( result , it , doc , lineCounter ) ) ; } } return result ; } function convertPair ( node , parent , doc , lineCounter ) { const keyNode = < Node > node . key ; const valueNode = < Node > node . value ; const rangeStart = keyNode . range [ 0 ] ; let rangeEnd = keyNode . range [ 1 ] ; let nodeEnd = keyNode . range [ 2 ] ; if ( valueNode ) { rangeEnd = valueNode . range [ 1 ] ; nodeEnd = valueNode . range [ 2 ] ; } const result = new PropertyASTNodeImpl ( parent as ObjectASTNodeImpl , node , ... toFixedOffsetLength ( [ rangeStart , rangeEnd , nodeEnd ] , lineCounter ) ) ; if ( isAlias ( keyNode ) ) { const keyAlias = new StringASTNodeImpl ( parent , keyNode , ... toOffsetLength ( keyNode . range ) ) ; keyAlias . value = keyNode . source ; result . keyNode = keyAlias ; } else { result . keyNode = < StringASTNodeImpl > convertAST ( result , keyNode , doc , lineCounter ) ; } result . valueNode = convertAST ( result , valueNode , doc , lineCounter ) ; return result ; } function convertSeq ( node , parent , doc , lineCounter ) { const result = new ArrayASTNodeImpl ( parent , node , ... toOffsetLength ( node . range ) ) ; for ( const it of node . items ) { if ( isNode ( it ) ) { result . children . push ( convertAST ( result , it , doc , lineCounter ) ) ; } } return result ; } function convertScalar ( node , parent ) { if ( node . value === null ) { return new NullASTNodeImpl ( parent , node , ... toOffsetLength ( node . range ) ) ; } switch ( typeof node . value ) { case 'string' : { const result = new StringASTNodeImpl ( parent , node , ... toOffsetLength ( node . range ) ) ; result . value = node . value ; return result ; } case 'boolean' : return new BooleanASTNodeImpl ( parent , node , node . value , ... toOffsetLength ( node . range ) ) ; case 'number' : { const result = new NumberASTNodeImpl ( parent , node , ... toOffsetLength ( node . range ) ) ; result . value = node . value ; result . isInteger = Number . isInteger ( result . value ) ; return result ; } } } function convertAlias ( node , parent , doc , lineCounter ) { refDepth ++ ; const resolvedNode = node . resolve ( doc ) ; if ( resolvedNode ) { return convertAST ( parent , resolvedNode , doc , lineCounter ) ; } else { const resultNode = new StringASTNodeImpl ( parent , node , ... toOffsetLength ( node . range ) ) ; resultNode . value = node . source ; return resultNode ; } } export function toOffsetLength ( range ) { return [ range [ 0 ] , range [ 1 ] - range [ 0 ] ] ; } param range param lineCounter returns function toFixedOffsetLength ( range , lineCounter ) { const start = lineCounter . linePos ( range [ 0 ] ) ; const end = lineCounter . linePos ( range [ 1 ] ) ; const result = [ range [ 0 ] , range [ 1 ] - range [ 0 ] ] ; if ( start . line !== end . line && ( lineCounter . lineStarts . length !== end . line || end . col === 1 ) ) { result [ 1 ] -- ; } return result ; } function collectFlowMapRange ( node ) { let start = Number . MAX_SAFE_INTEGER ; let end = 0 ; for ( const it of node . items ) { if ( isPair ( it ) ) { if ( isNode ( it . key ) ) { if ( it . key . range && it . key . range [ 0 ] <= start ) { start = it . key . range [ 0 ] ; } } if ( isNode ( it . value ) ) { if ( it . value . range && it . value . range [ 2 ] >= end ) { end = it . value . range [ 2 ] ; } } } } return [ start , end , end ] ; }