import type { IAttr , IDocument , IParentNode , ITagNode } from 'svg-vdom' ; import type { TDynamicObj } from '../../typings' ; import { ITag } from '../../typings/node' ; import { IStyleAttr } from '../../typings/style' ; import { cantCollapseAttributes , transformAttributes } from '../const/definitions' ; import { regularAttr } from '../const/regular-attr' ; import { checkApply } from '../style/check-apply' ; import { parseStyle } from '../style/parse' ; import { styleToValue } from '../style/style-to-value' ; import { hasProp } from '../utils/has-prop' ; import { parseStyleTree } from '../xml/parse-style-tree' ; type TAttrObj = TDynamicObj < IAttr > ; const collapseAttributes = ( node1 , node2 ) => { const attrObj = { } ; node1 . attributes . forEach ( attr => { attrObj [ attr . fullname ] = attr ; } ) ; node2 . attributes . forEach ( attr => { if ( hasProp ( attrObj , attr . fullname ) ) { if ( transformAttributes . includes ( attr . fullname ) ) { attrObj [ attr . fullname ] . value = `${ attr . value } ${ attrObj [ attr . fullname ] . value }` ; } } else { node1 . setAttribute ( attr . name , attr . value , attr . namespace ) ; attrObj [ attr . fullname ] = attr ; } } ) ; } ; const checkStyleTrans = ( dom , node ) => { parseStyleTree ( dom ) ; const styleAttr = node . getAttribute ( 'style' ) ; if ( styleAttr ) { const styleList = parseStyle ( styleAttr ) ; const transStyleList = new Map < ITagNode , IStyleAttr > ( ) ; for ( let si = styleList . length ; si -- ; ) { const styleItem = styleList [ si ] ; const styleDefine = regularAttr [ styleItem . fullname ] ; if ( styleDefine . applyTo . includes ( 'g' ) ) { return ; } const affectChildren = node . children . filter ( ( child ) => checkApply ( styleDefine , child , dom ) && child . styles ?. [ styleItem . fullname ] ?. from === 'inherit' ) ; if ( affectChildren . length === 0 ) continue ; if ( affectChildren . length === 1 ) { transStyleList . set ( affectChildren [ 0 ] , styleItem ) ; continue ; } return ; } for ( const [ childNode , styleItem ] of transStyleList ) { const childStyle = parseStyle ( childNode . getAttribute ( 'style' ) ?? '' ) ; styleItem . important = false ; childStyle . push ( styleItem ) ; childNode . setAttribute ( 'style' , styleToValue ( childStyle ) ) ; } node . removeAttribute ( 'style' ) ; } } ; const cantCollapse = ( node ) => node . attributes . filter ( attr => cantCollapseAttributes . includes ( attr . fullname ) ) . length ; export const collapseG = async ( dom ) : Promise < void > => new Promise ( resolve => { const gTags = dom . querySelectorAll ( 'g' ) as ITagNode [ ] ; for ( let i = gTags . length ; i -- ; ) { const node = gTags [ i ] ; const children = node . children ; if ( ! children . length ) { node . remove ( ) ; continue ; } checkStyleTrans ( dom , node ) ; if ( ! cantCollapse ( node ) ) { if ( children . length === 1 ) { const childNode = children [ 0 ] as ITagNode ; collapseAttributes ( childNode , node ) ; ( node . parentNode as IParentNode ) . replaceChild ( childNode , node ) ; } else if ( ! node . attributes . length ) { ( node . parentNode as IParentNode ) . replaceChild ( children , node ) ; } } } resolve ( ) ; } ) ;