@@ -24,7 +24,6 @@ const resolver = new ResolverFactory({
2424 extensions : [ ".tsx" , ".ts" , ".jsx" , ".js" ] ,
2525} ) ;
2626
27- // Type guards for better type safety
2827export function isFunction ( node : Node ) : node is OxcFunction {
2928 const functionTypes : FunctionType [ ] = [
3029 "FunctionDeclaration" ,
@@ -73,29 +72,28 @@ export function traverseChildren(
7372 return true ;
7473 }
7574 }
76- } else if ( child && typeof child === "object" ) {
77- if ( callback ( child as Node ) ) return true ;
75+ } else if ( child && typeof child === "object" && callback ( child as Node ) ) {
76+ return true ;
7877 }
7978 }
8079 return false ;
8180}
8281
83- export function hasRenderSSRCallInAST ( ast : unknown , code : string ) : boolean {
82+ export function hasRenderSSRCallInAST ( ast : Node , code : string ) : boolean {
8483 const renderSSRIdentifiers = new Set < string > ( [ "renderSSR" ] ) ;
8584 let hasRenderSSRCallInCode = false ;
8685
8786 function walkForDetection ( node : Node ) : boolean {
8887 if ( ! node || typeof node !== "object" ) return false ;
8988
90- // Track renderSSR imports and aliases
91- if ( isImportDeclaration ( node ) ) {
92- if ( ! node . source ?. value || ! node . specifiers ) return false ;
93-
89+ if ( isImportDeclaration ( node ) && node . source ?. value && node . specifiers ) {
9490 for ( const spec of node . specifiers ) {
9591 if ( spec . type === "ImportSpecifier" ) {
9692 const importSpec = spec as ImportSpecifier ;
97- if ( importSpec . imported . type !== "Identifier" ) continue ;
98- if ( importSpec . imported . name === "renderSSR" ) {
93+ if (
94+ importSpec . imported . type === "Identifier" &&
95+ importSpec . imported . name === "renderSSR"
96+ ) {
9997 renderSSRIdentifiers . add ( importSpec . local . name ) ;
10098 }
10199 } else if ( spec . type === "ImportDefaultSpecifier" ) {
@@ -107,47 +105,36 @@ export function hasRenderSSRCallInAST(ast: unknown, code: string): boolean {
107105 }
108106 }
109107
110- // Track declared renderSSR functions (including TypeScript declares)
111- if ( isFunction ( node ) ) {
112- if ( node . id ?. name === "renderSSR" ) {
113- renderSSRIdentifiers . add ( "renderSSR" ) ;
114- }
108+ if ( isFunction ( node ) && node . id ?. name === "renderSSR" ) {
109+ renderSSRIdentifiers . add ( "renderSSR" ) ;
115110 }
116111
117- // Track variable aliases
118112 if ( isVariableDeclarator ( node ) ) {
119- if ( node . id . type !== "Identifier" ) return false ;
120- if ( node . init ?. type !== "Identifier" ) return false ;
121- if ( ! renderSSRIdentifiers . has ( node . init . name ) ) return false ;
122-
123- const bindingId = node . id as BindingIdentifier ;
124- renderSSRIdentifiers . add ( bindingId . name ) ;
113+ if (
114+ node . id . type === "Identifier" &&
115+ node . init ?. type === "Identifier" &&
116+ renderSSRIdentifiers . has ( node . init . name )
117+ ) {
118+ const bindingId = node . id as BindingIdentifier ;
119+ renderSSRIdentifiers . add ( bindingId . name ) ;
120+ }
125121 }
126122
127- // Check for renderSSR calls
128- if ( isCallExpression ( node ) ) {
129- if ( node . callee . type === "Identifier" ) {
130- if ( renderSSRIdentifiers . has ( node . callee . name ) ) {
131- hasRenderSSRCallInCode = true ;
132- return true ;
133- }
134- }
123+ if (
124+ isCallExpression ( node ) &&
125+ node . callee . type === "Identifier" &&
126+ renderSSRIdentifiers . has ( node . callee . name )
127+ ) {
128+ hasRenderSSRCallInCode = true ;
129+ return true ;
135130 }
136131
137- // Recursively check children
138132 return traverseChildren ( node , walkForDetection ) ;
139133 }
140134
141- walkForDetection ( ast as Node ) ;
135+ walkForDetection ( ast ) ;
142136
143- // If we have renderSSR calls, transform the code
144- // This handles both cases:
145- // 1. Explicit imports/declares with calls
146- // 2. Direct renderSSR calls (common in tests)
147- const hasCallsInString = code . includes ( "renderSSR(" ) ;
148- const result = hasRenderSSRCallInCode || hasCallsInString ;
149-
150- return result ;
137+ return hasRenderSSRCallInCode || code . includes ( "renderSSR(" ) ;
151138}
152139
153140export function extractPropsFromJSX (
@@ -160,20 +147,18 @@ export function extractPropsFromJSX(
160147 if ( attr . type !== "JSXAttribute" ) continue ;
161148
162149 const jsxAttr = attr as JSXAttribute ;
163- if ( jsxAttr . name . type !== "JSXIdentifier" ) continue ;
150+ if ( jsxAttr . name . type !== "JSXIdentifier" || ! jsxAttr . value ) continue ;
164151
165152 const propName = jsxAttr . name . name ;
166- if ( ! jsxAttr . value ) continue ;
167-
168- if ( isJSXExpressionContainer ( jsxAttr . value ) ) {
169- // Extract the raw source code of the expression
170- if ( jsxAttr . value . expression . type !== "JSXEmptyExpression" ) {
171- const exprSpan = jsxAttr . value . expression as Node & Span ;
172- const expressionCode = sourceCode . slice ( exprSpan . start , exprSpan . end ) ;
173- props [ propName ] = expressionCode ;
174- }
153+
154+ if (
155+ isJSXExpressionContainer ( jsxAttr . value ) &&
156+ jsxAttr . value . expression . type !== "JSXEmptyExpression"
157+ ) {
158+ const exprSpan = jsxAttr . value . expression as Node & Span ;
159+ const expressionCode = sourceCode . slice ( exprSpan . start , exprSpan . end ) ;
160+ props [ propName ] = expressionCode ;
175161 } else if ( jsxAttr . value . type === "Literal" ) {
176- // For string literals, use the actual value
177162 const literal = jsxAttr . value as { value : unknown } ;
178163 props [ propName ] = JSON . stringify ( literal . value ) ;
179164 }
@@ -191,19 +176,16 @@ function fallbackResolveComponentPath(
191176 testFileId : string ,
192177) : string {
193178 if ( ! importPath . startsWith ( "." ) ) {
194- // Absolute import, add extension if needed
195179 return importPath . endsWith ( ".tsx" ) || importPath . endsWith ( ".ts" )
196180 ? importPath
197181 : `${ importPath } .tsx` ;
198182 }
199183
200- // Relative import - resolve relative to test file
201184 const testFileDir = dirname ( testFileId ) ;
202185 const resolvedPath = resolve ( testFileDir , importPath ) ;
203186 const projectRoot = process . cwd ( ) ;
204187 let componentPath = `./${ relative ( projectRoot , resolvedPath ) } ` ;
205188
206- // Add extension if needed
207189 if ( ! componentPath . endsWith ( ".tsx" ) && ! componentPath . endsWith ( ".ts" ) ) {
208190 componentPath += ".tsx" ;
209191 }
@@ -219,12 +201,9 @@ export function resolveComponentPath(
219201 const result = resolver . sync ( testFileDir , importPath ) ;
220202
221203 if ( result . error || ! result . path ) {
222- const errorMsg = result . error || "No path resolved" ;
223-
224204 console . warn (
225- `[oxc-resolver] Could not resolve "${ importPath } " from "${ testFileId } ": ${ errorMsg } . Using fallback resolution. If this is not a test file, this might be a bug .` ,
205+ `[oxc-resolver] Could not resolve "${ importPath } " from "${ testFileId } ": ${ result . error || "No path resolved" } . Using fallback resolution .` ,
226206 ) ;
227-
228207 return fallbackResolveComponentPath ( importPath , testFileId ) ;
229208 }
230209
@@ -235,10 +214,13 @@ export function resolveComponentPath(
235214}
236215
237216export function hasCommandsImport ( node : Node ) : boolean {
238- if ( ! isImportDeclaration ( node ) ) return false ;
239-
240- if ( node . source ?. value !== "@vitest/browser/context" ) return false ;
241- if ( ! node . specifiers ) return false ;
217+ if (
218+ ! isImportDeclaration ( node ) ||
219+ node . source ?. value !== "@vitest/browser/context" ||
220+ ! node . specifiers
221+ ) {
222+ return false ;
223+ }
242224
243225 return node . specifiers . some (
244226 ( spec ) =>
0 commit comments