@@ -3,45 +3,58 @@ import { NodePath, types as t } from '@babel/core'
33
44const elements = [ 'svg' , 'Svg' ]
55
6- const createTitleElement = (
6+ type tag = 'title' | 'desc'
7+
8+ export interface Options {
9+ tag : tag | null
10+ }
11+
12+ interface State {
13+ opts : Options
14+ }
15+
16+ const createTagElement = (
17+ tag : tag ,
718 children : t . JSXExpressionContainer [ ] = [ ] ,
819 attributes : ( t . JSXAttribute | t . JSXSpreadAttribute ) [ ] = [ ] ,
920) => {
10- const title = t . jsxIdentifier ( 'title' )
21+ const eleName = t . jsxIdentifier ( tag )
1122 return t . jsxElement (
12- t . jsxOpeningElement ( title , attributes ) ,
13- t . jsxClosingElement ( title ) ,
23+ t . jsxOpeningElement ( eleName , attributes ) ,
24+ t . jsxClosingElement ( eleName ) ,
1425 children ,
1526 )
1627}
1728
18- const createTitleIdAttribute = ( ) =>
29+ const createTagIdAttribute = ( tag : tag ) =>
1930 t . jsxAttribute (
2031 t . jsxIdentifier ( 'id' ) ,
21- t . jsxExpressionContainer ( t . identifier ( 'titleId' ) ) ,
32+ t . jsxExpressionContainer ( t . identifier ( ` ${ tag } Id` ) ) ,
2233 )
2334
24- const addTitleIdAttribute = (
35+ const addTagIdAttribute = (
36+ tag : tag ,
2537 attributes : ( t . JSXAttribute | t . JSXSpreadAttribute ) [ ] ,
2638) => {
2739 const existingId = attributes . find (
2840 ( attribute ) => t . isJSXAttribute ( attribute ) && attribute . name . name === 'id' ,
2941 ) as t . JSXAttribute | undefined
3042
3143 if ( ! existingId ) {
32- return [ ...attributes , createTitleIdAttribute ( ) ]
44+ return [ ...attributes , createTagIdAttribute ( tag ) ]
3345 }
3446 existingId . value = t . jsxExpressionContainer (
3547 t . isStringLiteral ( existingId . value )
36- ? t . logicalExpression ( '||' , t . identifier ( 'titleId' ) , existingId . value )
37- : t . identifier ( 'titleId' ) ,
48+ ? t . logicalExpression ( '||' , t . identifier ( ` ${ tag } Id` ) , existingId . value )
49+ : t . identifier ( ` ${ tag } Id` ) ,
3850 )
3951 return attributes
4052}
4153
4254const plugin = ( ) => ( {
4355 visitor : {
44- JSXElement ( path : NodePath < t . JSXElement > ) {
56+ JSXElement ( path : NodePath < t . JSXElement > , state : State ) {
57+ const tag = state . opts . tag || 'title'
4558 if ( ! elements . length ) return
4659
4760 const openingElement = path . get ( 'openingElement' )
@@ -54,22 +67,24 @@ const plugin = () => ({
5467 return
5568 }
5669
57- const getTitleElement = (
70+ const getTagElement = (
5871 existingTitle ?: t . JSXElement ,
5972 ) : t . JSXExpressionContainer => {
60- const titleExpression = t . identifier ( 'title' )
73+ const tagExpression = t . identifier ( tag )
6174 if ( existingTitle ) {
62- existingTitle . openingElement . attributes = addTitleIdAttribute (
75+ existingTitle . openingElement . attributes = addTagIdAttribute (
76+ tag ,
6377 existingTitle . openingElement . attributes ,
6478 )
6579 }
6680 const conditionalTitle = t . conditionalExpression (
67- titleExpression ,
68- createTitleElement (
69- [ t . jsxExpressionContainer ( titleExpression ) ] ,
81+ tagExpression ,
82+ createTagElement (
83+ tag ,
84+ [ t . jsxExpressionContainer ( tagExpression ) ] ,
7085 existingTitle
7186 ? existingTitle . openingElement . attributes
72- : [ createTitleIdAttribute ( ) ] ,
87+ : [ createTagIdAttribute ( tag ) ] ,
7388 ) ,
7489 t . nullLiteral ( ) ,
7590 )
@@ -80,7 +95,7 @@ const plugin = () => ({
8095 t . conditionalExpression (
8196 t . binaryExpression (
8297 '===' ,
83- titleExpression ,
98+ tagExpression ,
8499 t . identifier ( 'undefined' ) ,
85100 ) ,
86101 existingTitle ,
@@ -92,25 +107,25 @@ const plugin = () => ({
92107 }
93108
94109 // store the title element
95- let titleElement : t . JSXExpressionContainer | null = null
110+ let tagElement : t . JSXExpressionContainer | null = null
96111
97112 const hasTitle = path . get ( 'children' ) . some ( ( childPath ) => {
98- if ( childPath . node === titleElement ) return false
113+ if ( childPath . node === tagElement ) return false
99114 if ( ! childPath . isJSXElement ( ) ) return false
100115 const name = childPath . get ( 'openingElement' ) . get ( 'name' )
101116 if ( ! name . isJSXIdentifier ( ) ) return false
102- if ( name . node . name !== 'title' ) return false
103- titleElement = getTitleElement ( childPath . node )
104- childPath . replaceWith ( titleElement )
117+ if ( name . node . name !== tag ) return false
118+ tagElement = getTagElement ( childPath . node )
119+ childPath . replaceWith ( tagElement )
105120 return true
106121 } )
107122
108123 // create a title element if not already create
109- titleElement = titleElement || getTitleElement ( )
124+ tagElement = tagElement || getTagElement ( )
110125 if ( ! hasTitle ) {
111126 // path.unshiftContainer is not working well :(
112127 // path.unshiftContainer('children', titleElement)
113- path . node . children . unshift ( titleElement )
128+ path . node . children . unshift ( tagElement )
114129 path . replaceWith ( path . node )
115130 }
116131 } ,
0 commit comments