@@ -7,7 +7,7 @@ export function parseDirective(
77 traceDirective : t . Directive ,
88 locationDescription : string
99) {
10- // extract the component name from "use trace ..."
10+ // I. Extract the component name from "use trace ..."
1111 const maybeMatches = traceDirective . value . value
1212 . match ( / u s e t r a c e \s + ( \S + ) (?: \s + ( \S + ) ) ? $ / )
1313 ?. filter ( ( x ) => x !== undefined ) ;
@@ -44,33 +44,64 @@ export function parseDirective(
4444
4545 let isFunctionComponent = true ;
4646
47- if ( 'id' in path . node && path . node . id ?. name ) {
48- // function or class declaration
49- componentName ??= path . node . id . name ;
50- } else if (
51- path . parent . type === 'VariableDeclarator' &&
52- path . parent . id . type === 'Identifier'
47+ // II. Attempt to read displayName or name, if componentName is still undefined
48+ if (
49+ ! componentName &&
50+ ( path . node . type === 'FunctionDeclaration' ||
51+ path . node . type === 'FunctionExpression' ||
52+ path . node . type === 'ArrowFunctionExpression' )
5353 ) {
54- // variable assignment
55- componentName ??= path . parent . id . name ;
56- } else if (
57- path . parent . type === 'ObjectProperty' &&
58- path . parent . key . type === 'Identifier'
59- ) {
60- // object property assignment
61- componentName ??= path . parent . key . name ;
62- } else if (
63- path . parent . type === 'ClassMethod' &&
64- path . parent . key . type === 'Identifier'
65- ) {
66- // class method
67- isFunctionComponent = false ;
68- componentName ??= path . parent . key . name ;
69- } else if ( path . parent . type === 'ExportDefaultDeclaration' ) {
70- // anonymous export default
71- throw new Error (
72- `[Ottrelite] Identifier is an anonymous default export, which is not supported! The tracer must be given a unique name. Localization: ${ locationDescription } .`
54+ // look for .displayName or .name assignments in parent scope
55+ const parent = path . findParent (
56+ ( p ) => p . isProgram ( ) || p . isBlockStatement ( )
7357 ) ;
58+ if ( parent ) {
59+ parent . traverse ( {
60+ AssignmentExpression ( assignPath ) {
61+ if (
62+ assignPath . node . left . type === 'MemberExpression' &&
63+ assignPath . node . left . property . type === 'Identifier' &&
64+ ( assignPath . node . left . property . name === 'displayName' ||
65+ assignPath . node . left . property . name === 'name' ) &&
66+ assignPath . node . right . type === 'StringLiteral'
67+ ) {
68+ componentName = assignPath . node . right . value ;
69+ }
70+ } ,
71+ } ) ;
72+ }
73+ }
74+
75+ // III. Infer the name from context, if componentName is still undefined
76+ if ( ! componentName ) {
77+ if ( 'id' in path . node && path . node . id ?. name ) {
78+ // function or class declaration
79+ componentName ??= path . node . id . name ;
80+ } else if (
81+ path . parent . type === 'VariableDeclarator' &&
82+ path . parent . id . type === 'Identifier'
83+ ) {
84+ // variable assignment
85+ componentName ??= path . parent . id . name ;
86+ } else if (
87+ path . parent . type === 'ObjectProperty' &&
88+ path . parent . key . type === 'Identifier'
89+ ) {
90+ // object property assignment
91+ componentName ??= path . parent . key . name ;
92+ } else if (
93+ path . parent . type === 'ClassMethod' &&
94+ path . parent . key . type === 'Identifier'
95+ ) {
96+ // class method
97+ isFunctionComponent = false ;
98+ componentName ??= path . parent . key . name ;
99+ } else if ( path . parent . type === 'ExportDefaultDeclaration' ) {
100+ // anonymous export default
101+ throw new Error (
102+ `[Ottrelite] Identifier is an anonymous default export, which is not supported! The tracer must be given a unique name. Localization: ${ locationDescription } .`
103+ ) ;
104+ }
74105 }
75106
76107 return {
0 commit comments