Skip to content

Commit 91062d7

Browse files
committed
Emit correct occurrences for JSX attributes
1 parent 14910a2 commit 91062d7

File tree

3 files changed

+75
-32
lines changed

3 files changed

+75
-32
lines changed

snapshots/input/react/src/LoaderInput.tsx

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,20 @@ import React from 'react'
22

33
/** Takes loading prop, input component as child */
44
interface Props {
5-
loading: boolean
6-
children: React.ReactNode
7-
className?: string
5+
loading: boolean
6+
children: React.ReactNode
87
}
98

10-
export const LoaderInput: React.FunctionComponent<Props> = ({ loading, children, className }) => (
11-
<div className="hello">
12-
{children}
13-
{loading && <p className="spinner">spinner</p>}
14-
</div>
9+
export const LoaderInput: React.FunctionComponent<Props> = ({
10+
loading,
11+
children,
12+
}) => (
13+
<div className="hello">
14+
{children}
15+
{loading && <p>spinner</p>}
16+
</div>
1517
)
18+
19+
export const LoaderInput2: React.FunctionComponent<Props> = props => {
20+
return <LoaderInput loading={true} children={props.children} />
21+
}

snapshots/output/react/src/LoaderInput.tsx

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,35 +4,49 @@
44
/** Takes loading prop, input component as child */
55
interface Props {
66
// ^^^^^ definition example 1.0.0 src/`LoaderInput.tsx`/Props#
7-
loading: boolean
8-
// ^^^^^^^ definition example 1.0.0 src/`LoaderInput.tsx`/Props#loading.
9-
children: React.ReactNode
10-
// ^^^^^^^^ definition example 1.0.0 src/`LoaderInput.tsx`/Props#children.
11-
// ^^^^^ reference @types/react 17.0.0 `index.d.ts`/React/
12-
// ^^^^^^^^^ reference local 0
13-
className?: string
14-
// ^^^^^^^^^ definition example 1.0.0 src/`LoaderInput.tsx`/Props#className.
7+
loading: boolean
8+
// ^^^^^^^ definition example 1.0.0 src/`LoaderInput.tsx`/Props#loading.
9+
children: React.ReactNode
10+
// ^^^^^^^^ definition example 1.0.0 src/`LoaderInput.tsx`/Props#children.
11+
// ^^^^^ reference @types/react 17.0.0 `index.d.ts`/React/
12+
// ^^^^^^^^^ reference local 0
1513
}
1614

17-
export const LoaderInput: React.FunctionComponent<Props> = ({ loading, children, className }) => (
15+
export const LoaderInput: React.FunctionComponent<Props> = ({
1816
// ^^^^^^^^^^^ definition example 1.0.0 src/`LoaderInput.tsx`/LoaderInput.
1917
// ^^^^^ reference @types/react 17.0.0 `index.d.ts`/React/
2018
// ^^^^^^^^^^^^^^^^^ reference @types/react 17.0.0 `index.d.ts`/React/FunctionComponent#
2119
// ^^^^^ reference example 1.0.0 src/`LoaderInput.tsx`/Props#
22-
// ^^^^^^^ reference local 4
23-
// ^^^^^^^^ reference local 5
24-
// ^^^^^^^^^ reference local 6
25-
<div className="hello">
26-
// ^^^ reference @types/react 17.0.0 `index.d.ts`/global/JSX/IntrinsicElements#div.
27-
// ^^^^^^^^^ reference local 11
28-
{children}
29-
// ^^^^^^^^ reference local 5
30-
{loading && <p className="spinner">spinner</p>}
31-
// ^^^^^^^ reference local 4
32-
// ^ reference @types/react 17.0.0 `index.d.ts`/global/JSX/IntrinsicElements#p.
33-
// ^^^^^^^^^ reference local 17
34-
// ^ reference @types/react 17.0.0 `index.d.ts`/global/JSX/IntrinsicElements#p.
35-
</div>
36-
// ^^^ reference @types/react 17.0.0 `index.d.ts`/global/JSX/IntrinsicElements#div.
20+
loading,
21+
// ^^^^^^^ reference local 4
22+
children,
23+
// ^^^^^^^^ reference local 5
24+
}) => (
25+
<div className="hello">
26+
// ^^^ reference @types/react 17.0.0 `index.d.ts`/global/JSX/IntrinsicElements#div.
27+
// ^^^^^^^^^ reference @types/react 17.0.0 `index.d.ts`/React/HTMLAttributes#className.
28+
{children}
29+
// ^^^^^^^^ reference local 5
30+
{loading && <p>spinner</p>}
31+
// ^^^^^^^ reference local 4
32+
// ^ reference @types/react 17.0.0 `index.d.ts`/global/JSX/IntrinsicElements#p.
33+
// ^ reference @types/react 17.0.0 `index.d.ts`/global/JSX/IntrinsicElements#p.
34+
</div>
35+
// ^^^ reference @types/react 17.0.0 `index.d.ts`/global/JSX/IntrinsicElements#div.
3736
)
3837

38+
export const LoaderInput2: React.FunctionComponent<Props> = props => {
39+
// ^^^^^^^^^^^^ definition example 1.0.0 src/`LoaderInput.tsx`/LoaderInput2.
40+
// ^^^^^ reference @types/react 17.0.0 `index.d.ts`/React/
41+
// ^^^^^^^^^^^^^^^^^ reference @types/react 17.0.0 `index.d.ts`/React/FunctionComponent#
42+
// ^^^^^ reference example 1.0.0 src/`LoaderInput.tsx`/Props#
43+
// ^^^^^ definition local 7
44+
return <LoaderInput loading={true} children={props.children} />
45+
// ^^^^^^^^^^^ reference example 1.0.0 src/`LoaderInput.tsx`/LoaderInput.
46+
// ^^^^^^^ reference example 1.0.0 src/`LoaderInput.tsx`/Props#loading.
47+
// ^^^^^^^^ reference example 1.0.0 src/`LoaderInput.tsx`/Props#children.
48+
// ^^^^^ reference local 7
49+
// ^^^^^^^^ reference example 1.0.0 src/`LoaderInput.tsx`/Props#children.
50+
// ^^^^^^^^ reference local 11
51+
}
52+

src/FileIndexer.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,29 @@ export class FileIndexer {
181181
)
182182
)
183183
}
184+
185+
if (ts.isJsxAttribute(node)) {
186+
// NOTE(olafurpg): the logic below is a bit convoluted but I spent several
187+
// hours and failed to come up with a cleaner solution. JSX attributes
188+
// have custom typechecking rules, as documented here
189+
// https://www.typescriptlang.org/docs/handbook/jsx.html#type-checking The
190+
// only way to access the actual symbol we want to reference appears to go
191+
// through the JSX opening element, which is the grandparent of the JSX
192+
// attribute node. Through the signature of the opening element, we get
193+
// the permitted attributes by querying the type of the first parameter.
194+
const jsxElement = node.parent.parent
195+
const props = this.checker
196+
.getResolvedSignature(jsxElement)
197+
?.getParameters()?.[0]
198+
if (props) {
199+
const tpe = this.checker.getTypeOfSymbolAtLocation(props, node)
200+
const property = tpe.getProperty(node.name.text)
201+
for (const decl of property?.declarations || []) {
202+
return this.lsifSymbol(decl)
203+
}
204+
}
205+
}
206+
184207
const owner = this.lsifSymbol(node.parent)
185208
if (owner.isEmpty() || owner.isLocal()) {
186209
return this.newLocalSymbol(node)

0 commit comments

Comments
 (0)