import { parse , X2jOptionsOptional } from "fast-xml-parser" ; import { AllHtmlEntities } from "html-entities" ; export const isObject = < T extends Object > ( x ) : x is T => ! ! x && typeof x === 'object' ; export const isArray = ( x ) : x is unknown [ ] => Array . isArray ( x ) ; export const isString = ( x ) : x is string => typeof ( x ) === "string" ; export const isNumber = ( x ) : x is number => typeof x === "number" ; export const isNativeError = ( e ) : e is Error => ! ! e && e instanceof Error ; export const isUndefined = ( x ) : x is undefined => typeof ( x ) === "undefined" ; export function JSON2AbapXML ( original , root = "DATA" ) { let inner = "" ; for ( const key of Object . keys ( original ) ) if ( original [ key ] ) inner = `${ inner }\n<${ key }>${ encodeEntity ( original [ key ] ) || "" }</${ key }>` ; else inner = `${ inner }\n<${ key }/>` ; return `<?xml version="1.0" encoding="UTF-8"?><asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
    <asx:values>
      <${ root }>
        ${ inner }
      </${ root }>
    </asx:values>
  </asx:abap>` ; } export function xmlNode ( xml , ... path ) { let current = xml ; path . some ( key => { if ( isObject ( current ) ) current = current [ key ] ; return ! current ; } ) ; return current ; } export function xmlFlatArray < T > ( xml , ... path ) { if ( ! xml ) return [ ] ; if ( path . length === 0 ) { if ( isArray ( xml ) ) return xml as any [ ] ; else return [ xml ] ; } if ( isArray ( xml ) ) return xml . reduce ( ( arr , x ) => [ ... arr , ... xmlFlatArray ( x , ... path ) ] , [ ] ) ; if ( isObject ( xml ) ) { const [ idx , ... rest ] = path ; return xmlFlatArray ( xml [ idx ] , ... rest ) ; } return [ ] ; } export function xmlArray < T > ( xml , ... path ) { const node = xmlNode ( xml , ... path ) ; if ( node ) { if ( isArray ( node ) ) return node as any [ ] ; else return [ node ] ; } return [ ] ; } const ok = Object . keys ; export const xmlRoot = ( o ) => o [ ok ( o ) [ 0 ] ] ; export const stripNs = ( x ) => x && ok ( x ) . reduce ( ( obj , key ) => { const nk = key . split ( ":" ) . slice ( 1 ) . join ( ":" ) || key ; if ( nk in obj ) obj [ key ] = key ; else obj [ nk ] = x [ key ] ; return obj ; } , { } as any ) ; export const xmlNodeAttr = ( n ) => n && ok ( n ) . filter ( k => k . match ( /^(?!@_xmlns)@_/ ) ) . reduce ( ( part , cur ) => { part [ cur . replace ( /^@_/ , "" ) ] = n [ cur ] ; return part ; } , { } ) ; export const fullParse = ( xml , options = { } ) => parse ( xml , { ignoreAttributes : false , trimValues : false , parseAttributeValue : true , ... options } ) ; export function toInt ( x ? ) { if ( ! x ) return 0 ; if ( x . match ( /^\s*\d*\s*$/ ) ) return Number . parseInt ( x , 10 ) ; return 0 ; } export const parseSapDate = ( d ) => { const match = d . match ( /(\d\d\d\d)(\d\d)(\d\d)/ ) ; if ( ! match ) return new Date ( ) ; const [ Y , M , D ] = match . slice ( 1 ) ; return Date . UTC ( toInt ( Y ) , toInt ( M ) - 1 , toInt ( D ) ) ; } ; export const toSapDate = ( d ) => d . getUTCFullYear ( ) * 10000 + ( d . getUTCMonth ( ) + 1 ) * 100 + d . getUTCDate ( ) ; export const parseJsonDate = ( d ) => new Date ( Date . parse ( d ) ) ; export const [ decodeEntity , encodeEntity ] = ( ( ) => { let entities ; return [ ( s ) => { if ( ! entities ) entities = new AllHtmlEntities ( ) ; return entities . decode ( s ) ; } , ( s ) => { if ( ! entities ) entities = new AllHtmlEntities ( ) ; return entities . encode ( s ) ; } ] ; } ) ( ) ; export function btoa ( s ) { return Buffer . from ( s ) . toString ( "base64" ) ; } export function parts ( whole , pattern ) { if ( ! isString ( whole ) ) return [ ] ; const match = whole . match ( pattern ) ; return match ? match . slice ( 1 ) : [ ] ; } export const followUrl = ( base , extra ) => { if ( extra . match ( /^\.\// ) ) { base = base . replace ( /[^\/]*$/ , "" ) ; extra = extra . replace ( /^\.\// , "" ) ; } else extra = extra . replace ( /^\// , "" ) ; base = base . replace ( /\/$/ , "" ) ; return base + "/" + extra ; } ; export const boolFromAbap = ( x ) => x === "X" ; export function formatQS ( raw ) { const val = ( key , x ) : string => isArray ( x ) ? x . map ( e => val ( key , e ) ) . join ( "&" ) : `${ key }=${ encodeURIComponent ( x ) }` ; return Object . getOwnPropertyNames ( raw ) . map ( k => val ( k , raw [ k ] ) ) . join ( "&" ) ; } export const toXmlAttributes = ( o , prefix ) => { const sep = prefix ? ":" : "" ; return o ? Object . getOwnPropertyNames ( o ) . sort ( ) . map ( k => `${ prefix }${ sep }${ k . replace ( /^@_/ , "" ) }="${ o [ k ] }"` ) . join ( " " ) : "" ; } ;