import { Kind , load , YamlMap , YAMLMapping , YAMLNode , YAMLScalar , YAMLSequence , } from "yaml-ast-parser" ; import { kindKey , positionKey } from "./keys" ; import { DataKind , DataWithPosition , Position } from "./types" ; const isBetween = ( start , pos , end ) => pos <= end && pos >= start ; const calculatePosition = ( input , { start , end } ) => { const lines = input . split ( /\n/ ) ; const position = { start : { line : - 1 , column : - 1 , } , end : { line : - 1 , column : - 1 , } , } ; let sum = 0 ; for ( const i of lines . keys ( ) ) { const line = lines [ i ] ; const ls = sum ; const le = sum + line . length ; if ( position . start . line === - 1 && isBetween ( ls , start , le ) ) { position . start . line = i + 1 ; position . start . column = start - ls + 1 ; } if ( position . end . line === - 1 && isBetween ( ls , end , le ) ) { position . end . line = i + 1 ; position . end . column = end - ls + 1 ; } sum = le + 1 ; } return position ; } ; const wrappedScalar = ( Constructor , kind , value , position ) => { const v = new Constructor ( value ) ; v [ positionKey ] = position ; v [ kindKey ] = kind ; return v ; } ; const returnNull = ( ) => null ; const wrappedNull = ( position ) => ( { [ positionKey ] : position , [ kindKey ] : "null" , valueOf : returnNull as any , } ) ; const visitorByNodeKind = { } ; const walk = ( nodes , input , ctx = { } ) => { const onNode = ( node , ctx2 , fallback ) => { const visitor = node ? visitorByNodeKind [ node . kind ] : visitorByNodeKind [ Kind . SCALAR ] ; return visitor ? visitor ( node , input , ctx2 ) : fallback ; } ; const walkObj = ( ) => nodes . reduce ( ( sum , node ) => { return onNode ( node , sum , sum ) ; } , ctx ) ; const walkArr = ( ) => nodes . map ( ( node ) => onNode ( node , ctx , null ) , ctx ) . filter ( Boolean ) ; return Array . isArray ( ctx ) ? walkArr ( ) : walkObj ( ) ; } ; visitorByNodeKind [ Kind . MAP ] = ( node , input , ctx ) => { return Object . assign ( walk ( node . mappings , input ) , { [ positionKey ] : calculatePosition ( input , { start : node . startPosition , end : node . endPosition , } ) , [ kindKey ] : "object" , } ) ; } ; visitorByNodeKind [ Kind . MAPPING ] = ( node , input , ctx ) => { const value = walk ( [ node . value ] , input ) ; if ( node . value === null ) { return Object . assign ( ctx , { [ node . key . value ] : wrappedNull ( calculatePosition ( input , { start : node . startPosition , end : node . endPosition , } ) ) , } ) ; } value [ positionKey ] = calculatePosition ( input , { start : node . startPosition , end : node . endPosition , } ) ; return Object . assign ( ctx , { [ node . key . value ] : value , } ) ; } ; visitorByNodeKind [ Kind . SCALAR ] = ( node , input ) => { if ( ! node ) { return ; } const position = calculatePosition ( input , { start : node . startPosition , end : node . endPosition , } ) ; if ( typeof node . valueObject === "boolean" ) { return wrappedScalar ( Boolean , "boolean" , node . valueObject , position ) ; } else if ( typeof node . valueObject === "number" ) { return wrappedScalar ( Number , "number" , node . valueObject , position ) ; } else if ( node . valueObject === null || node . value === null ) { return wrappedNull ( position ) ; } return wrappedScalar ( String , "string" , node . value , position ) ; } ; visitorByNodeKind [ Kind . SEQ ] = ( node , input ) => { const items = walk ( node . items , input , [ ] ) ; items [ positionKey ] = calculatePosition ( input , { start : node . startPosition , end : node . endPosition , } ) ; items [ kindKey ] = "array" ; return items ; } ; export const fromYaml = ( input ) : DataWithPosition => walk ( [ load ( input ) ] , input ) ;