Skip to content

Commit

Permalink
Resolve JSX intrinsic elements to index signature symbols (#55245)
Browse files Browse the repository at this point in the history
  • Loading branch information
Andarist committed Aug 7, 2023
1 parent e936eb1 commit 5ea2952
Show file tree
Hide file tree
Showing 45 changed files with 750 additions and 335 deletions.
71 changes: 40 additions & 31 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30680,15 +30680,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (!isErrorType(intrinsicElementsType)) {
// Property case
if (!isIdentifier(node.tagName) && !isJsxNamespacedName(node.tagName)) return Debug.fail();
const intrinsicProp = getPropertyOfType(intrinsicElementsType, isJsxNamespacedName(node.tagName) ? getEscapedTextOfJsxNamespacedName(node.tagName) : node.tagName.escapedText);
const propName = isJsxNamespacedName(node.tagName) ? getEscapedTextOfJsxNamespacedName(node.tagName) : node.tagName.escapedText;
const intrinsicProp = getPropertyOfType(intrinsicElementsType, propName);
if (intrinsicProp) {
links.jsxFlags |= JsxFlags.IntrinsicNamedElement;
return links.resolvedSymbol = intrinsicProp;
}

// Intrinsic string indexer case
const indexSignatureType = getIndexTypeOfType(intrinsicElementsType, stringType);
if (indexSignatureType) {
const indexSymbol = getApplicableIndexSymbol(intrinsicElementsType, getStringLiteralType(unescapeLeadingUnderscores(propName)));
if (indexSymbol) {
links.jsxFlags |= JsxFlags.IntrinsicIndexedElement;
return links.resolvedSymbol = indexSymbol;
}

if (getTypeOfPropertyOrIndexSignatureOfType(intrinsicElementsType, propName)) {
links.jsxFlags |= JsxFlags.IntrinsicIndexedElement;
return links.resolvedSymbol = intrinsicElementsType.symbol;
}
Expand Down Expand Up @@ -30916,8 +30922,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return links.resolvedJsxElementAttributesType = getTypeOfSymbol(symbol) || errorType;
}
else if (links.jsxFlags & JsxFlags.IntrinsicIndexedElement) {
const propName = isJsxNamespacedName(node.tagName) ? getEscapedTextOfJsxNamespacedName(node.tagName) : node.tagName.escapedText;
return links.resolvedJsxElementAttributesType =
getIndexTypeOfType(getJsxType(JsxNames.IntrinsicElements, node), stringType) || errorType;
getApplicableIndexInfoForName(getJsxType(JsxNames.IntrinsicElements, node), propName)?.type || errorType;
}
else {
return links.resolvedJsxElementAttributesType = errorType;
Expand Down Expand Up @@ -45709,33 +45716,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (name.kind === SyntaxKind.PropertyAccessExpression) {
checkPropertyAccessExpression(name, CheckMode.Normal);
if (!links.resolvedSymbol) {
const expressionType = checkExpressionCached(name.expression);
const infos = getApplicableIndexInfos(expressionType, getLiteralTypeFromPropertyName(name.name));
if (infos.length && (expressionType as ObjectType).members) {
const resolved = resolveStructuredTypeMembers(expressionType as ObjectType);
const symbol = resolved.members.get(InternalSymbolName.Index);
if (infos === getIndexInfosOfType(expressionType)) {
links.resolvedSymbol = symbol;
}
else if (symbol) {
const symbolLinks = getSymbolLinks(symbol);
const declarationList = mapDefined(infos, i => i.declaration);
const nodeListId = map(declarationList, getNodeId).join(",");
if (!symbolLinks.filteredIndexSymbolCache) {
symbolLinks.filteredIndexSymbolCache = new Map();
}
if (symbolLinks.filteredIndexSymbolCache.has(nodeListId)) {
links.resolvedSymbol = symbolLinks.filteredIndexSymbolCache.get(nodeListId)!;
}
else {
const copy = createSymbol(SymbolFlags.Signature, InternalSymbolName.Index);
copy.declarations = mapDefined(infos, i => i.declaration);
copy.parent = expressionType.aliasSymbol ? expressionType.aliasSymbol : expressionType.symbol ? expressionType.symbol : getSymbolAtLocation(copy.declarations[0].parent);
symbolLinks.filteredIndexSymbolCache.set(nodeListId, copy);
links.resolvedSymbol = symbolLinks.filteredIndexSymbolCache.get(nodeListId)!;
}
}
}
links.resolvedSymbol = getApplicableIndexSymbol(checkExpressionCached(name.expression), getLiteralTypeFromPropertyName(name.name));
}
}
else {
Expand All @@ -45762,6 +45743,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return undefined;
}

function getApplicableIndexSymbol(type: Type, keyType: Type) {
const infos = getApplicableIndexInfos(type, keyType);
if (infos.length && (type as ObjectType).members) {
const symbol = getIndexSymbolFromSymbolTable(resolveStructuredTypeMembers(type as ObjectType).members);
if (infos === getIndexInfosOfType(type)) {
return symbol;
}
else if (symbol) {
const symbolLinks = getSymbolLinks(symbol);
const declarationList = mapDefined(infos, i => i.declaration);
const nodeListId = map(declarationList, getNodeId).join(",");
if (!symbolLinks.filteredIndexSymbolCache) {
symbolLinks.filteredIndexSymbolCache = new Map();
}
if (symbolLinks.filteredIndexSymbolCache.has(nodeListId)) {
return symbolLinks.filteredIndexSymbolCache.get(nodeListId)!;
}
else {
const copy = createSymbol(SymbolFlags.Signature, InternalSymbolName.Index);
copy.declarations = mapDefined(infos, i => i.declaration);
copy.parent = type.aliasSymbol ? type.aliasSymbol : type.symbol ? type.symbol : getSymbolAtLocation(copy.declarations[0].parent);
symbolLinks.filteredIndexSymbolCache.set(nodeListId, copy);
return copy;
}
}
}
}

/**
* Recursively resolve entity names and jsdoc instance references:
* 1. K#m as K.prototype.m for a class (or other value) K
Expand Down
16 changes: 8 additions & 8 deletions tests/baselines/reference/inlineJsxAndJsxFragPragma.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ import {h, Fragment} from "./renderer";
>Fragment : Symbol(Fragment, Decl(preacty.tsx, 4, 10))

<><div></div></>
>div : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>div : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>div : Symbol(JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))
>div : Symbol(JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))

=== snabbdomy.tsx ===
/* @jsx jsx */
Expand All @@ -44,8 +44,8 @@ import {jsx} from "./renderer";
>jsx : Symbol(jsx, Decl(snabbdomy.tsx, 2, 8))

<><span></span></>
>span : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>span : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>span : Symbol(JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))
>span : Symbol(JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))

=== preacty-only-fragment.tsx ===
/**
Expand Down Expand Up @@ -93,8 +93,8 @@ import {h, Fragment} from "./renderer";
>Fragment : Symbol(Fragment, Decl(preacty-no-fragment.tsx, 4, 10))

<div></div>
>div : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>div : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>div : Symbol(JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))
>div : Symbol(JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))

=== snabbdomy-no-fragment.tsx ===
/* @jsx jsx */
Expand All @@ -103,8 +103,8 @@ import {jsx} from "./renderer";
>jsx : Symbol(jsx, Decl(snabbdomy-no-fragment.tsx, 2, 8))

<div></div>
>div : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>div : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>div : Symbol(JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))
>div : Symbol(JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))

=== preacty-only-component.tsx ===
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ import {createElement, Fragment} from "./react";
>Fragment : Symbol(Fragment, Decl(reacty.tsx, 0, 22))

<><span></span></>
>span : Symbol(JSX.IntrinsicElements, Decl(react.d.ts, 1, 19))
>span : Symbol(JSX.IntrinsicElements, Decl(react.d.ts, 1, 19))
>span : Symbol(JSX.IntrinsicElements.__index, Decl(react.d.ts, 2, 37))
>span : Symbol(JSX.IntrinsicElements.__index, Decl(react.d.ts, 2, 37))

=== preacty.tsx ===
/**
Expand All @@ -51,8 +51,8 @@ import {h, Frag} from "./preact";
>Frag : Symbol(Frag, Decl(preacty.tsx, 4, 10))

<><div></div></>
>div : Symbol(JSX.IntrinsicElements, Decl(react.d.ts, 1, 19))
>div : Symbol(JSX.IntrinsicElements, Decl(react.d.ts, 1, 19))
>div : Symbol(JSX.IntrinsicElements.__index, Decl(react.d.ts, 2, 37))
>div : Symbol(JSX.IntrinsicElements.__index, Decl(react.d.ts, 2, 37))

=== snabbdomy.tsx ===
/**
Expand All @@ -63,8 +63,8 @@ import {h} from "./snabbdom";
>h : Symbol(h, Decl(snabbdomy.tsx, 4, 8))

<><div></div></>
>div : Symbol(JSX.IntrinsicElements, Decl(react.d.ts, 1, 19))
>div : Symbol(JSX.IntrinsicElements, Decl(react.d.ts, 1, 19))
>div : Symbol(JSX.IntrinsicElements.__index, Decl(react.d.ts, 2, 37))
>div : Symbol(JSX.IntrinsicElements.__index, Decl(react.d.ts, 2, 37))

=== mix-n-match.tsx ===
/* @jsx h */
Expand All @@ -76,6 +76,6 @@ import {Fragment} from "./react";
>Fragment : Symbol(Fragment, Decl(mix-n-match.tsx, 3, 8))

<><span></span></>
>span : Symbol(JSX.IntrinsicElements, Decl(react.d.ts, 1, 19))
>span : Symbol(JSX.IntrinsicElements, Decl(react.d.ts, 1, 19))
>span : Symbol(JSX.IntrinsicElements.__index, Decl(react.d.ts, 2, 37))
>span : Symbol(JSX.IntrinsicElements.__index, Decl(react.d.ts, 2, 37))

20 changes: 10 additions & 10 deletions tests/baselines/reference/inlineJsxFactoryDeclarations.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ import * as React from "./renderer";
>React : Symbol(React, Decl(otherreacty.tsx, 1, 6))

<h></h>
>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>h : Symbol(JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))
>h : Symbol(JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))

=== other.tsx ===
/** @jsx h */
Expand All @@ -45,8 +45,8 @@ import { dom as h } from "./renderer"

export const prerendered = <h></h>;
>prerendered : Symbol(prerendered, Decl(other.tsx, 2, 12))
>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>h : Symbol(JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))
>h : Symbol(JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))

=== othernoalias.tsx ===
/** @jsx otherdom */
Expand All @@ -55,26 +55,26 @@ import { otherdom } from "./renderer"

export const prerendered2 = <h></h>;
>prerendered2 : Symbol(prerendered2, Decl(othernoalias.tsx, 2, 12))
>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>h : Symbol(JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))
>h : Symbol(JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))

=== reacty.tsx ===
import React from "./renderer"
>React : Symbol(React, Decl(reacty.tsx, 0, 6))

export const prerendered3 = <h></h>;
>prerendered3 : Symbol(prerendered3, Decl(reacty.tsx, 1, 12))
>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>h : Symbol(JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))
>h : Symbol(JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))

=== index.tsx ===
/** @jsx dom */
import { dom } from "./renderer"
>dom : Symbol(dom, Decl(index.tsx, 1, 8))

<h></h>
>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>h : Symbol(JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))
>h : Symbol(JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))

export * from "./other";
export * from "./othernoalias";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export const MySFC = (props: {x: number, y: number, children?: predom.JSX.Elemen
>predom : Symbol(predom, Decl(component.tsx, 1, 8))
>JSX : Symbol(predom.JSX, Decl(renderer2.d.ts, 0, 25))
>Element : Symbol(predom.JSX.Element, Decl(renderer2.d.ts, 4, 9))
>p : Symbol(predom.JSX.IntrinsicElements, Decl(renderer2.d.ts, 1, 19))
>p : Symbol(predom.JSX.IntrinsicElements.__index, Decl(renderer2.d.ts, 2, 37))
>props.x : Symbol(x, Decl(component.tsx, 3, 30))
>props : Symbol(props, Decl(component.tsx, 3, 22))
>x : Symbol(x, Decl(component.tsx, 3, 30))
Expand All @@ -129,7 +129,7 @@ export const MySFC = (props: {x: number, y: number, children?: predom.JSX.Elemen
>props.y : Symbol(y, Decl(component.tsx, 3, 40))
>props : Symbol(props, Decl(component.tsx, 3, 22))
>y : Symbol(y, Decl(component.tsx, 3, 40))
>p : Symbol(predom.JSX.IntrinsicElements, Decl(renderer2.d.ts, 1, 19))
>p : Symbol(predom.JSX.IntrinsicElements.__index, Decl(renderer2.d.ts, 2, 37))

export class MyClass implements predom.JSX.Element {
>MyClass : Symbol(MyClass, Decl(component.tsx, 3, 164))
Expand All @@ -155,7 +155,7 @@ export class MyClass implements predom.JSX.Element {
>render : Symbol(MyClass.render, Decl(component.tsx, 7, 89))

return <p>
>p : Symbol(predom.JSX.IntrinsicElements, Decl(renderer2.d.ts, 1, 19))
>p : Symbol(predom.JSX.IntrinsicElements.__index, Decl(renderer2.d.ts, 2, 37))

{this.props.x} + {this.props.y} = {this.props.x + this.props.y}
>this.props.x : Symbol(x, Decl(component.tsx, 7, 31))
Expand Down Expand Up @@ -187,7 +187,7 @@ export class MyClass implements predom.JSX.Element {
>children : Symbol(children, Decl(component.tsx, 7, 52))

</p>;
>p : Symbol(predom.JSX.IntrinsicElements, Decl(renderer2.d.ts, 1, 19))
>p : Symbol(predom.JSX.IntrinsicElements.__index, Decl(renderer2.d.ts, 2, 37))
}
}
export const tree = <MySFC x={1} y={2}><MyClass x={3} y={4} /><MyClass x={5} y={6} /></MySFC>
Expand All @@ -204,8 +204,8 @@ export const tree = <MySFC x={1} y={2}><MyClass x={3} y={4} /><MyClass x={5} y={
>MySFC : Symbol(MySFC, Decl(component.tsx, 3, 12))

export default <h></h>
>h : Symbol(predom.JSX.IntrinsicElements, Decl(renderer2.d.ts, 1, 19))
>h : Symbol(predom.JSX.IntrinsicElements, Decl(renderer2.d.ts, 1, 19))
>h : Symbol(predom.JSX.IntrinsicElements.__index, Decl(renderer2.d.ts, 2, 37))
>h : Symbol(predom.JSX.IntrinsicElements.__index, Decl(renderer2.d.ts, 2, 37))

=== index.tsx ===
/** @jsx dom */
Expand All @@ -224,8 +224,8 @@ let elem = prerendered;

elem = <h></h>; // Expect assignability error here
>elem : Symbol(elem, Decl(index.tsx, 3, 3))
>h : Symbol(dom.JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>h : Symbol(dom.JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>h : Symbol(dom.JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))
>h : Symbol(dom.JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))

const DOMSFC = (props: {x: number, y: number, children?: dom.JSX.Element[]}) => <p>{props.x} + {props.y} = {props.x + props.y}{props.children}</p>;
>DOMSFC : Symbol(DOMSFC, Decl(index.tsx, 6, 5))
Expand All @@ -236,7 +236,7 @@ const DOMSFC = (props: {x: number, y: number, children?: dom.JSX.Element[]}) =>
>dom : Symbol(dom, Decl(index.tsx, 1, 8))
>JSX : Symbol(dom.JSX, Decl(renderer.d.ts, 0, 22))
>Element : Symbol(dom.JSX.Element, Decl(renderer.d.ts, 4, 9))
>p : Symbol(dom.JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>p : Symbol(dom.JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))
>props.x : Symbol(x, Decl(index.tsx, 6, 24))
>props : Symbol(props, Decl(index.tsx, 6, 16))
>x : Symbol(x, Decl(index.tsx, 6, 24))
Expand All @@ -252,7 +252,7 @@ const DOMSFC = (props: {x: number, y: number, children?: dom.JSX.Element[]}) =>
>props.children : Symbol(children, Decl(index.tsx, 6, 45))
>props : Symbol(props, Decl(index.tsx, 6, 16))
>children : Symbol(children, Decl(index.tsx, 6, 45))
>p : Symbol(dom.JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>p : Symbol(dom.JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))

class DOMClass implements dom.JSX.Element {
>DOMClass : Symbol(DOMClass, Decl(index.tsx, 6, 147))
Expand All @@ -278,7 +278,7 @@ class DOMClass implements dom.JSX.Element {
>render : Symbol(DOMClass.render, Decl(index.tsx, 10, 86))

return <p>{this.props.x} + {this.props.y} = {this.props.x + this.props.y}{...this.props.children}</p>;
>p : Symbol(dom.JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>p : Symbol(dom.JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))
>this.props.x : Symbol(x, Decl(index.tsx, 10, 31))
>this.props : Symbol(DOMClass.props, Decl(index.tsx, 10, 16))
>this : Symbol(DOMClass, Decl(index.tsx, 6, 147))
Expand All @@ -304,7 +304,7 @@ class DOMClass implements dom.JSX.Element {
>this : Symbol(DOMClass, Decl(index.tsx, 6, 147))
>props : Symbol(DOMClass.props, Decl(index.tsx, 10, 16))
>children : Symbol(children, Decl(index.tsx, 10, 52))
>p : Symbol(dom.JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>p : Symbol(dom.JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ import { predom } from "./renderer2"
>predom : Symbol(predom, Decl(component.tsx, 1, 8))

export default <h></h>
>h : Symbol(predom.JSX.IntrinsicElements, Decl(renderer2.d.ts, 1, 19))
>h : Symbol(predom.JSX.IntrinsicElements, Decl(renderer2.d.ts, 1, 19))
>h : Symbol(predom.JSX.IntrinsicElements.__index, Decl(renderer2.d.ts, 2, 37))
>h : Symbol(predom.JSX.IntrinsicElements.__index, Decl(renderer2.d.ts, 2, 37))

=== index.tsx ===
/** @jsx dom */
Expand All @@ -104,6 +104,6 @@ let elem = prerendered;

elem = <h></h>; // Expect assignability error here
>elem : Symbol(elem, Decl(index.tsx, 3, 3))
>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>h : Symbol(JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))
>h : Symbol(JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))

Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@ import {dom} from "./renderer";
>dom : Symbol(dom, Decl(reacty.tsx, 1, 8))

<h></h>
>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>h : Symbol(JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))
>h : Symbol(JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))

=== index.tsx ===
import { p } from "./renderer";
>p : Symbol(p, Decl(index.tsx, 0, 8))

<h></h>
>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
>h : Symbol(JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))
>h : Symbol(JSX.IntrinsicElements.__index, Decl(renderer.d.ts, 2, 37))

0 comments on commit 5ea2952

Please sign in to comment.