@@ -49,13 +49,18 @@ function maybeNodeValue(node: Node): { text: string; loc: SourceLocation } {
4949export type MacroJsxContext = MacroJsContext & {
5050 elementIndex : ( ) => number
5151 transImportName : string
52+ jsxPlaceholderAttribute ?: string
53+ jsxPlaceholderDefaults ?: Record < string , string >
54+ elementsTracking : Map < string , JSXElement >
5255}
5356
5457export type MacroJsxOpts = {
5558 stripNonEssentialProps : boolean
5659 stripMessageProp : boolean
5760 transImportName : string
5861 isLinguiIdentifier : ( node : Identifier , macro : JsMacroName ) => boolean
62+ jsxPlaceholderAttribute ?: string
63+ jsxPlaceholderDefaults ?: Record < string , string >
5964}
6065
6166const choiceComponentAttributesWhitelist = [
@@ -86,6 +91,9 @@ export class MacroJSX {
8691 ) ,
8792 transImportName : opts . transImportName ,
8893 elementIndex : makeCounter ( ) ,
94+ jsxPlaceholderAttribute : opts . jsxPlaceholderAttribute ,
95+ jsxPlaceholderDefaults : opts . jsxPlaceholderDefaults ,
96+ elementsTracking : new Map ( ) ,
8997 }
9098 }
9199
@@ -351,18 +359,100 @@ export class MacroJSX {
351359 }
352360
353361 tokenizeElement = ( path : NodePath < JSXElement > ) : ElementToken => {
354- // !!! Important: Calculate element index before traversing children.
355- // That way outside elements are numbered before inner elements. (...and it looks pretty).
356- const name = this . ctx . elementIndex ( )
362+ const { jsxPlaceholderAttribute, jsxPlaceholderDefaults, elementsTracking } = this . ctx
363+
364+ const node = path . node
365+ const openingElement = node . openingElement
366+
367+ let value : typeof node = { ...node }
368+ let newOpeningElement : typeof openingElement = { ...openingElement }
369+ let baseName : string | undefined = undefined
370+
371+ if ( jsxPlaceholderAttribute ) {
372+ const attributes = newOpeningElement . attributes
373+ const attrIndex = attributes . findIndex (
374+ ( attr ) =>
375+ attr . type === "JSXAttribute" &&
376+ attr . name . name === jsxPlaceholderAttribute
377+ )
378+
379+ if ( attrIndex !== - 1 ) {
380+ const attr = attributes [ attrIndex ] as JSXAttribute
381+ if ( attr . value && attr . value . type === "StringLiteral" ) {
382+ baseName = attr . value . value
383+ }
384+
385+ const newAttributes = [ ...attributes ]
386+ newAttributes . splice ( attrIndex , 1 )
387+
388+ newOpeningElement = {
389+ ...newOpeningElement ,
390+ attributes : newAttributes ,
391+ }
392+ value = {
393+ ...value ,
394+ openingElement : newOpeningElement ,
395+ }
396+ }
397+ }
398+
399+ if ( ! baseName && jsxPlaceholderDefaults ) {
400+ const tagName = newOpeningElement . name
401+ if ( tagName . type === "JSXIdentifier" ) {
402+ const defaultName = jsxPlaceholderDefaults [ tagName . name ]
403+ if ( defaultName ) {
404+ baseName = defaultName
405+ }
406+ }
407+ }
408+
409+ let name : string | number
410+ if ( ! baseName ) {
411+ name = this . ctx . elementIndex ( )
412+ elementsTracking . set ( String ( name ) , value )
413+ } else {
414+ let suffix = 1
415+ let testName = baseName
416+ let existingElement = elementsTracking . get ( testName )
417+
418+ const areAttributesEqual = (
419+ attrs1 : typeof newOpeningElement . attributes ,
420+ attrs2 : typeof newOpeningElement . attributes
421+ ) => {
422+ if ( attrs1 . length !== attrs2 . length ) return false
423+ return attrs1 . every ( ( attr , i ) =>
424+ this . types . isNodesEquivalent ( attr , attrs2 [ i ] )
425+ )
426+ }
427+
428+ while ( existingElement ) {
429+ if (
430+ areAttributesEqual (
431+ existingElement . openingElement . attributes ,
432+ newOpeningElement . attributes
433+ )
434+ ) {
435+ break
436+ }
437+ suffix ++
438+ testName = `${ baseName } ${ suffix } `
439+ existingElement = elementsTracking . get ( testName )
440+ }
441+
442+ name = testName
443+ if ( ! existingElement ) {
444+ elementsTracking . set ( name , value )
445+ }
446+ }
357447
358448 return {
359449 type : "element" ,
360450 name,
361451 value : {
362- ...path . node ,
452+ ...value ,
363453 children : [ ] ,
364454 openingElement : {
365- ...path . node . openingElement ,
455+ ...newOpeningElement ,
366456 selfClosing : true ,
367457 } ,
368458 } ,
0 commit comments