Skip to content

Commit 2f26a0d

Browse files
committed
Update coverage
1 parent 3ac61cd commit 2f26a0d

2 files changed

Lines changed: 179 additions & 3 deletions

File tree

src/resolver.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,11 @@ export class ImportResolver {
5757
fileExists: (filePath) =>
5858
this.host.fileExists(filePath) || ts.sys.fileExists(filePath),
5959
getCurrentDirectory: () => path.dirname(normalizedFromFilePath),
60-
getDirectories: (directoryPath) => ts.sys.getDirectories(directoryPath),
60+
getDirectories: ts.sys.getDirectories,
6161
readFile: (filePath) =>
6262
this.host.readFile(filePath) ?? ts.sys.readFile(filePath),
63-
realpath: (filePath) => ts.sys.realpath?.(filePath) ?? filePath,
64-
useCaseSensitiveFileNames: () => ts.sys.useCaseSensitiveFileNames,
63+
realpath: ts.sys.realpath,
64+
useCaseSensitiveFileNames: ts.sys.useCaseSensitiveFileNames,
6565
}
6666

6767
const result = ts.resolveModuleName(

test/analyzer.test.ts

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,182 @@ void test('resolves tsconfig path aliases when mapping component types', () => {
222222
}
223223
})
224224

225+
void test('clear() resets all caches and re-analyses from scratch', () => {
226+
const project = createProject({
227+
'Page.tsx': [
228+
"import Button from './Button';",
229+
'',
230+
'export default function Page() {',
231+
' return <Button />;',
232+
'}',
233+
].join('\n'),
234+
'Button.tsx': [
235+
"'use client';",
236+
'',
237+
'export default function Button() {',
238+
' return <button />;',
239+
'}',
240+
].join('\n'),
241+
})
242+
243+
try {
244+
const analyzer = createAnalyzer(project.host)
245+
const filePath = project.filePath('Page.tsx')
246+
const source = project.readFile('Page.tsx')
247+
const sig = project.signature('Page.tsx')
248+
249+
const before = analyzer.analyzeDocument(filePath, source, sig)
250+
assert.equal(before.length, 1)
251+
assert.equal(before[0]?.kind, 'client')
252+
253+
analyzer.clear()
254+
255+
const after = analyzer.analyzeDocument(filePath, source, sig)
256+
assert.equal(after.length, 1)
257+
assert.equal(after[0]?.kind, 'client')
258+
} finally {
259+
project[Symbol.dispose]()
260+
}
261+
})
262+
263+
void test('recognizes forwardRef-wrapped local components', () => {
264+
const project = createProject({
265+
'Card.tsx': [
266+
"'use client';",
267+
'',
268+
'const Button = forwardRef((props) => <button />);',
269+
'',
270+
'export function Card() {',
271+
' return <Button />;',
272+
'}',
273+
].join('\n'),
274+
})
275+
276+
try {
277+
const analyzer = createAnalyzer(project.host)
278+
const filePath = project.filePath('Card.tsx')
279+
const usages = analyzer.analyzeDocument(
280+
filePath,
281+
project.readFile('Card.tsx'),
282+
project.signature('Card.tsx'),
283+
)
284+
285+
assert.equal(usages.length, 1)
286+
assert.equal(usages[0]?.kind, 'client')
287+
assert.equal(usages[0]?.tagName, 'Button')
288+
} finally {
289+
project[Symbol.dispose]()
290+
}
291+
})
292+
293+
void test('resolves namespaced JSX like <UI.Button />', () => {
294+
const project = createProject({
295+
'Page.tsx': [
296+
"import * as UI from './ui';",
297+
'',
298+
'export default function Page() {',
299+
' return <UI.Button />;',
300+
'}',
301+
].join('\n'),
302+
'ui.tsx': [
303+
"'use client';",
304+
'',
305+
'export function Button() {',
306+
' return <button />;',
307+
'}',
308+
].join('\n'),
309+
})
310+
311+
try {
312+
const analyzer = createAnalyzer(project.host)
313+
const filePath = project.filePath('Page.tsx')
314+
const source = project.readFile('Page.tsx')
315+
const usages = analyzer.analyzeDocument(
316+
filePath,
317+
source,
318+
project.signature('Page.tsx'),
319+
)
320+
321+
assert.equal(usages.length, 1)
322+
assert.equal(usages[0]?.kind, 'client')
323+
assert.equal(usages[0]?.tagName, 'UI.Button')
324+
} finally {
325+
project[Symbol.dispose]()
326+
}
327+
})
328+
329+
void test('resolves bare package imports through node_modules', () => {
330+
const project = createProject({
331+
'Page.tsx': [
332+
"import Button from 'my-ui';",
333+
'',
334+
'export default function Page() {',
335+
' return <Button />;',
336+
'}',
337+
].join('\n'),
338+
'node_modules/my-ui/package.json': JSON.stringify({
339+
name: 'my-ui',
340+
main: './index.tsx',
341+
}),
342+
'node_modules/my-ui/index.tsx': [
343+
"'use client';",
344+
'',
345+
'export default function Button() {',
346+
' return <button />;',
347+
'}',
348+
].join('\n'),
349+
})
350+
351+
try {
352+
const analyzer = createAnalyzer(project.host)
353+
const filePath = project.filePath('Page.tsx')
354+
const usages = analyzer.analyzeDocument(
355+
filePath,
356+
project.readFile('Page.tsx'),
357+
project.signature('Page.tsx'),
358+
)
359+
360+
assert.equal(usages.length, 1)
361+
assert.equal(usages[0]?.kind, 'client')
362+
assert.equal(usages[0]?.tagName, 'Button')
363+
} finally {
364+
project[Symbol.dispose]()
365+
}
366+
})
367+
368+
void test('resolves deeply nested namespaced JSX like <UI.Forms.Input />', () => {
369+
const project = createProject({
370+
'Page.tsx': [
371+
"import * as UI from './ui';",
372+
'',
373+
'export default function Page() {',
374+
' return <UI.Forms.Input />;',
375+
'}',
376+
].join('\n'),
377+
'ui.tsx': [
378+
"'use client';",
379+
'',
380+
'export const Forms = { Input: () => <input /> };',
381+
].join('\n'),
382+
})
383+
384+
try {
385+
const analyzer = createAnalyzer(project.host)
386+
const filePath = project.filePath('Page.tsx')
387+
const usages = analyzer.analyzeDocument(
388+
filePath,
389+
project.readFile('Page.tsx'),
390+
project.signature('Page.tsx'),
391+
)
392+
393+
assert.equal(usages.length, 1)
394+
assert.equal(usages[0]?.kind, 'client')
395+
assert.equal(usages[0]?.tagName, 'UI.Forms.Input')
396+
} finally {
397+
project[Symbol.dispose]()
398+
}
399+
})
400+
225401
function createAnalyzer(host: SourceHost): ComponentLensAnalyzer {
226402
const resolver = new ImportResolver(host)
227403
return new ComponentLensAnalyzer(host, resolver)

0 commit comments

Comments
 (0)