Skip to content

[Wip] master stateless overload #13640

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 45 commits into from
Feb 15, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
5558406
Parse JSX attributes as its own unique AST node and bind the node
Nov 8, 2016
4671685
Use chooseOverload logic to pick JSX stateless function
Nov 8, 2016
41108db
Update emitter to use JSXAttributes node instead of JSXAttribute node…
Jan 18, 2017
16d1b5d
Add language service support for JSXAttributes
Nov 8, 2016
d9927d4
Update existed conformance tests
Nov 8, 2016
aea7d09
Add tests for using spread attributes resolution in JSX stateful comp…
Nov 8, 2016
b0fd66d
Add tests for using default attributes in JSX stateful component
Nov 8, 2016
9e3da08
Add tests for overload stateless function component
Nov 8, 2016
19d0548
Add tests for generic stateless function component
Nov 8, 2016
70ca18e
Add a test for contextual type in JSXAttributes
Nov 8, 2016
8ce7e37
Update react.d.ts used during tests
Nov 8, 2016
a0b7c2e
Cache react.d.ts library when running tests
Nov 8, 2016
2c15eab
Update conformance tests baselines
Nov 8, 2016
3d19782
Add language service tests
Nov 8, 2016
a44c3f2
Fix linting error
Nov 8, 2016
a39f9ef
Update calling to getSpreadType and using set function when adding va…
Jan 19, 2017
2fd5667
Update baselines
Jan 19, 2017
350f47a
Address comment: call getContextualType instead of accessing contextu…
Nov 14, 2016
6ce31d7
Address comment: stop widen type when checking for spread any;
Nov 14, 2016
747ab05
Refactor getJsxAttributeSymbolsFromJsxOpeningLikeElement to createJsx…
Nov 15, 2016
ab2e14f
Addressing code review in previous PR. Combining below commits
Jan 19, 2017
0b4f25c
Handle inference of function expression/arrow functions attribute
Jan 23, 2017
378f444
Add tests and update baselines
Jan 23, 2017
0ea5073
Report an error when can't infer but do not report an error for other…
Jan 23, 2017
a0cdc9d
Update comments
Jan 23, 2017
3e07398
Merge branch 'master' into wip-master-statelessOverload
Jan 24, 2017
9c33395
Fix linting error
Jan 24, 2017
a088cf4
Address code review: fix up comment
Jan 25, 2017
bcba51d
Address comment: remove reducdant check
Jan 25, 2017
989f9d8
Merge branch 'master' into wip-master-statelessOverload
Jan 26, 2017
fa56933
Update baselines from merging
Jan 26, 2017
ceb7720
Address PR: fix typo
Jan 31, 2017
42c0816
Merge branch 'master' into wip-master-statelessOverload
Jan 31, 2017
aea551c
Address code review
Feb 2, 2017
56f31c3
Address code review
Feb 3, 2017
bb7dea1
Address code review: fix comment
Feb 4, 2017
2e8f16b
Fix comments
Feb 9, 2017
d8936e9
Correctly handle union of JSX element type
Feb 9, 2017
328f5cc
Add conformance tests for union element type
Feb 9, 2017
e90a328
correctly handle the case when attributes type is empty object
Feb 9, 2017
d0dcee0
Add tests and baselines for union element type
Feb 9, 2017
6dec0f5
Add language service test when element type is a union type
Feb 9, 2017
e9a578c
Update comment
Feb 9, 2017
e5cfe5c
Merge branch 'master' into wip-master-statelessOverload
Feb 14, 2017
a52ccff
Update baseline adding of "__esModule"
Feb 14, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1364,6 +1364,7 @@ namespace ts {
case SyntaxKind.TypeLiteral:
case SyntaxKind.JSDocTypeLiteral:
case SyntaxKind.JSDocRecordType:
case SyntaxKind.JsxAttributes:
return ContainerFlags.IsContainer;

case SyntaxKind.InterfaceDeclaration:
Expand Down Expand Up @@ -1470,6 +1471,7 @@ namespace ts {
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.JSDocRecordType:
case SyntaxKind.JSDocTypeLiteral:
case SyntaxKind.JsxAttributes:
// Interface/Object-types always have their children added to the 'members' of
// their container. They are only accessible through an instance of their
// container, and are never in scope otherwise (even inside the body of the
Expand Down Expand Up @@ -1659,6 +1661,14 @@ namespace ts {
return bindAnonymousDeclaration(node, SymbolFlags.ObjectLiteral, "__object");
}

function bindJsxAttributes(node: JsxAttributes) {
return bindAnonymousDeclaration(node, SymbolFlags.ObjectLiteral, "__jsxAttributes");
}

function bindJsxAttribute(node: JsxAttribute, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags) {
return declareSymbolAndAddToSymbolTable(node, symbolFlags, symbolExcludes);
}

function bindAnonymousDeclaration(node: Declaration, symbolFlags: SymbolFlags, name: string) {
const symbol = createSymbol(symbolFlags, name);
addDeclarationToSymbol(symbol, node, symbolFlags);
Expand Down Expand Up @@ -2080,6 +2090,12 @@ namespace ts {
case SyntaxKind.ModuleDeclaration:
return bindModuleDeclaration(<ModuleDeclaration>node);

// Jsx-attributes
case SyntaxKind.JsxAttributes:
return bindJsxAttributes(<JsxAttributes>node);
case SyntaxKind.JsxAttribute:
return bindJsxAttribute(<JsxAttribute>node, SymbolFlags.Property, SymbolFlags.PropertyExcludes);

// Imports and exports
case SyntaxKind.ImportEqualsDeclaration:
case SyntaxKind.NamespaceImport:
Expand Down Expand Up @@ -3156,6 +3172,7 @@ namespace ts {
case SyntaxKind.JsxText:
case SyntaxKind.JsxClosingElement:
case SyntaxKind.JsxAttribute:
case SyntaxKind.JsxAttributes:
case SyntaxKind.JsxSpreadAttribute:
case SyntaxKind.JsxExpression:
// These nodes are Jsx syntax.
Expand Down
648 changes: 480 additions & 168 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

18 changes: 15 additions & 3 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,8 @@ namespace ts {
return emitJsxClosingElement(<JsxClosingElement>node);
case SyntaxKind.JsxAttribute:
return emitJsxAttribute(<JsxAttribute>node);
case SyntaxKind.JsxAttributes:
return emitJsxAttributes(<JsxAttributes>node);
case SyntaxKind.JsxSpreadAttribute:
return emitJsxSpreadAttribute(<JsxSpreadAttribute>node);
case SyntaxKind.JsxExpression:
Expand Down Expand Up @@ -1891,15 +1893,21 @@ namespace ts {
write("<");
emitJsxTagName(node.tagName);
write(" ");
emitList(node, node.attributes, ListFormat.JsxElementAttributes);
// We are checking here so we won't re-enter the emiting pipeline and emit extra sourcemap
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: emiting → emitting

if (node.attributes.properties && node.attributes.properties.length > 0) {
emit(node.attributes);
}
write("/>");
}

function emitJsxOpeningElement(node: JsxOpeningElement) {
write("<");
emitJsxTagName(node.tagName);
writeIfAny(node.attributes, " ");
emitList(node, node.attributes, ListFormat.JsxElementAttributes);
writeIfAny(node.attributes.properties, " ");
// We are checking here so we won't re-enter the emitting pipeline and emit extra sourcemap
if (node.attributes.properties && node.attributes.properties.length > 0) {
emit(node.attributes);
}
write(">");
}

Expand All @@ -1913,6 +1921,10 @@ namespace ts {
write(">");
}

function emitJsxAttributes(node: JsxAttributes) {
emitList(node, node.properties, ListFormat.JsxElementAttributes);
}

function emitJsxAttribute(node: JsxAttribute) {
emit(node.name);
emitWithPrefix("=", node.initializer);
Expand Down
25 changes: 19 additions & 6 deletions src/compiler/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1381,28 +1381,28 @@ namespace ts {
: node;
}

export function createJsxSelfClosingElement(tagName: JsxTagNameExpression, attributes: JsxAttributeLike[]) {
export function createJsxSelfClosingElement(tagName: JsxTagNameExpression, attributes: JsxAttributes) {
const node = <JsxSelfClosingElement>createSynthesizedNode(SyntaxKind.JsxSelfClosingElement);
node.tagName = tagName;
node.attributes = createNodeArray(attributes);
node.attributes = attributes;
return node;
}

export function updateJsxSelfClosingElement(node: JsxSelfClosingElement, tagName: JsxTagNameExpression, attributes: JsxAttributeLike[]) {
export function updateJsxSelfClosingElement(node: JsxSelfClosingElement, tagName: JsxTagNameExpression, attributes: JsxAttributes) {
return node.tagName !== tagName
|| node.attributes !== attributes
? updateNode(createJsxSelfClosingElement(tagName, attributes), node)
: node;
}

export function createJsxOpeningElement(tagName: JsxTagNameExpression, attributes: JsxAttributeLike[]) {
export function createJsxOpeningElement(tagName: JsxTagNameExpression, attributes: JsxAttributes) {
const node = <JsxOpeningElement>createSynthesizedNode(SyntaxKind.JsxOpeningElement);
node.tagName = tagName;
node.attributes = createNodeArray(attributes);
node.attributes = attributes;
return node;
}

export function updateJsxOpeningElement(node: JsxOpeningElement, tagName: JsxTagNameExpression, attributes: JsxAttributeLike[]) {
export function updateJsxOpeningElement(node: JsxOpeningElement, tagName: JsxTagNameExpression, attributes: JsxAttributes) {
return node.tagName !== tagName
|| node.attributes !== attributes
? updateNode(createJsxOpeningElement(tagName, attributes), node)
Expand All @@ -1421,6 +1421,19 @@ namespace ts {
: node;
}

export function createJsxAttributes(properties: JsxAttributeLike[]) {
const jsxAttributes = <JsxAttributes>createSynthesizedNode(SyntaxKind.JsxAttributes);
jsxAttributes.properties = createNodeArray(properties);
return jsxAttributes;
}

export function updateJsxAttributes(jsxAttributes: JsxAttributes, properties: JsxAttributeLike[]) {
if (jsxAttributes.properties !== properties) {
return updateNode(createJsxAttributes(properties), jsxAttributes);
}
return jsxAttributes;
}

export function createJsxAttribute(name: Identifier, initializer: StringLiteral | JsxExpression) {
const node = <JsxAttribute>createSynthesizedNode(SyntaxKind.JsxAttribute);
node.name = name;
Expand Down
12 changes: 10 additions & 2 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,9 @@ namespace ts {
case SyntaxKind.JsxSelfClosingElement:
case SyntaxKind.JsxOpeningElement:
return visitNode(cbNode, (<JsxOpeningLikeElement>node).tagName) ||
visitNodes(cbNodes, (<JsxOpeningLikeElement>node).attributes);
visitNode(cbNode, (<JsxOpeningLikeElement>node).attributes);
case SyntaxKind.JsxAttributes:
return visitNodes(cbNodes, (<JsxAttributes>node).properties);
case SyntaxKind.JsxAttribute:
return visitNode(cbNode, (<JsxAttribute>node).name) ||
visitNode(cbNode, (<JsxAttribute>node).initializer);
Expand Down Expand Up @@ -3865,14 +3867,20 @@ namespace ts {
return result;
}

function parseJsxAttributes(): JsxAttributes {
const jsxAttributes = <JsxAttributes>createNode(SyntaxKind.JsxAttributes);
jsxAttributes.properties = parseList(ParsingContext.JsxAttributes, parseJsxAttribute);
return finishNode(jsxAttributes);
}

function parseJsxOpeningOrSelfClosingElement(inExpressionContext: boolean): JsxOpeningElement | JsxSelfClosingElement {
const fullStart = scanner.getStartPos();

parseExpected(SyntaxKind.LessThanToken);

const tagName = parseJsxElementName();
const attributes = parseJsxAttributes();

const attributes = parseList(ParsingContext.JsxAttributes, parseJsxAttribute);
let node: JsxOpeningLikeElement;

if (token() === SyntaxKind.GreaterThanToken) {
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/transformers/jsx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ namespace ts {
function visitJsxOpeningLikeElement(node: JsxOpeningLikeElement, children: JsxChild[], isChild: boolean, location: TextRange) {
const tagName = getTagName(node);
let objectProperties: Expression;
const attrs = node.attributes;
const attrs = node.attributes.properties;
if (attrs.length === 0) {
// When there are no attributes, React wants "null"
objectProperties = createNull();
Expand Down
33 changes: 20 additions & 13 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@
JsxOpeningElement,
JsxClosingElement,
JsxAttribute,
JsxAttributes,
JsxSpreadAttribute,
JsxExpression,

Expand Down Expand Up @@ -726,6 +727,7 @@
// SyntaxKind.BindingElement
// SyntaxKind.Property
// SyntaxKind.PropertyAssignment
// SyntaxKind.JsxAttribute
// SyntaxKind.ShorthandPropertyAssignment
// SyntaxKind.EnumMember
// SyntaxKind.JSDocPropertyTag
Expand Down Expand Up @@ -1444,7 +1446,7 @@
template: TemplateLiteral;
}

export type CallLikeExpression = CallExpression | NewExpression | TaggedTemplateExpression | Decorator;
export type CallLikeExpression = CallExpression | NewExpression | TaggedTemplateExpression | Decorator | JsxOpeningLikeElement;

export interface AsExpression extends Expression {
kind: SyntaxKind.AsExpression;
Expand Down Expand Up @@ -1481,35 +1483,38 @@
closingElement: JsxClosingElement;
}

/// Either the opening tag in a <Tag>...</Tag> pair, or the lone <Tag /> in a self-closing form
export type JsxOpeningLikeElement = JsxSelfClosingElement | JsxOpeningElement;

export type JsxAttributeLike = JsxAttribute | JsxSpreadAttribute;

export type JsxTagNameExpression = PrimaryExpression | PropertyAccessExpression;

export interface JsxAttributes extends ObjectLiteralExpressionBase<JsxAttributeLike> {
}

/// The opening element of a <Tag>...</Tag> JsxElement
export interface JsxOpeningElement extends Expression {
kind: SyntaxKind.JsxOpeningElement;
tagName: JsxTagNameExpression;
attributes: NodeArray<JsxAttribute | JsxSpreadAttribute>;
attributes: JsxAttributes;
}

/// A JSX expression of the form <TagName attrs />
export interface JsxSelfClosingElement extends PrimaryExpression {
kind: SyntaxKind.JsxSelfClosingElement;
tagName: JsxTagNameExpression;
attributes: NodeArray<JsxAttribute | JsxSpreadAttribute>;
attributes: JsxAttributes;
}

/// Either the opening tag in a <Tag>...</Tag> pair, or the lone <Tag /> in a self-closing form
export type JsxOpeningLikeElement = JsxSelfClosingElement | JsxOpeningElement;

export type JsxAttributeLike = JsxAttribute | JsxSpreadAttribute;

export interface JsxAttribute extends Node {
export interface JsxAttribute extends ObjectLiteralElement {
kind: SyntaxKind.JsxAttribute;
name: Identifier;
/// JSX attribute initializers are optional; <X y /> is sugar for <X y={true} />
initializer?: StringLiteral | JsxExpression;
}

export interface JsxSpreadAttribute extends Node {
export interface JsxSpreadAttribute extends ObjectLiteralElement {
kind: SyntaxKind.JsxSpreadAttribute;
expression: Expression;
}
Expand Down Expand Up @@ -2420,7 +2425,7 @@
/** Unlike `getExportsOfModule`, this includes properties of an `export =` value. */
/* @internal */ getExportsAndPropertiesOfModule(moduleSymbol: Symbol): Symbol[];

getJsxElementAttributesType(elementNode: JsxOpeningLikeElement): Type;
getAllAttributesTypeFromJsxOpeningLikeElement(elementNode: JsxOpeningLikeElement): Type;
getJsxIntrinsicTagNames(): Symbol[];
isOptionalParameter(node: ParameterDeclaration): boolean;
getAmbientModules(): Symbol[];
Expand Down Expand Up @@ -2812,7 +2817,7 @@
isVisible?: boolean; // Is this node visible
hasReportedStatementInAmbientContext?: boolean; // Cache boolean if we report statements in ambient context
jsxFlags?: JsxFlags; // flags for knowing what kind of element/attributes we're dealing with
resolvedJsxType?: Type; // resolved element attributes type of a JSX openinglike element
resolvedJsxElementAttributesType?: Type; // resolved element attributes type of a JSX openinglike element
hasSuperCall?: boolean; // recorded result when we try to find super-call. We only try to find one if this flag is undefined, indicating that we haven't made an attempt.
superCall?: ExpressionStatement; // Cached first super-call found in the constructor. Used in checking whether super is called before this-accessing
switchTypes?: Type[]; // Cached array of switch case expression types
Expand Down Expand Up @@ -2848,6 +2853,8 @@
/* @internal */
ContainsAnyFunctionType = 1 << 23, // Type is or contains object literal type
NonPrimitive = 1 << 24, // intrinsic object type
/* @internal */
JsxAttributes = 1 << 25, // Jsx attributes type

/* @internal */
Nullable = Undefined | Null,
Expand Down Expand Up @@ -3037,7 +3044,7 @@

/* @internal */
// Object literals are initially marked fresh. Freshness disappears following an assignment,
// before a type assertion, or when when an object literal's type is widened. The regular
// before a type assertion, or when an object literal's type is widened. The regular
// version of a fresh type is identical except for the TypeFlags.FreshObjectLiteral flag.
export interface FreshObjectLiteralType extends ResolvedType {
regularType: ResolvedType; // Regular version of fresh type
Expand Down
15 changes: 15 additions & 0 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1169,6 +1169,8 @@ namespace ts {

export function isCallLikeExpression(node: Node): node is CallLikeExpression {
switch (node.kind) {
case SyntaxKind.JsxOpeningElement:
case SyntaxKind.JsxSelfClosingElement:
case SyntaxKind.CallExpression:
case SyntaxKind.NewExpression:
case SyntaxKind.TaggedTemplateExpression:
Expand All @@ -1183,6 +1185,9 @@ namespace ts {
if (node.kind === SyntaxKind.TaggedTemplateExpression) {
return (<TaggedTemplateExpression>node).tag;
}
else if (isJsxOpeningLikeElement(node)) {
return node.tagName;
}

// Will either be a CallExpression, NewExpression, or Decorator.
return (<CallExpression | Decorator>node).expression;
Expand Down Expand Up @@ -3954,6 +3959,7 @@ namespace ts {
|| kind === SyntaxKind.ImportEqualsDeclaration
|| kind === SyntaxKind.ImportSpecifier
|| kind === SyntaxKind.InterfaceDeclaration
|| kind === SyntaxKind.JsxAttribute
|| kind === SyntaxKind.MethodDeclaration
|| kind === SyntaxKind.MethodSignature
|| kind === SyntaxKind.ModuleDeclaration
Expand Down Expand Up @@ -4066,6 +4072,11 @@ namespace ts {
|| kind === SyntaxKind.JsxText;
}

export function isJsxAttributes(node: Node): node is JsxAttributes {
const kind = node.kind;
return kind === SyntaxKind.JsxAttributes;
}

export function isJsxAttributeLike(node: Node): node is JsxAttributeLike {
const kind = node.kind;
return kind === SyntaxKind.JsxAttribute
Expand All @@ -4080,6 +4091,10 @@ namespace ts {
return node.kind === SyntaxKind.JsxAttribute;
}

export function isJsxOpeningLikeElement(node: Node): node is JsxOpeningLikeElement {
return node.kind === SyntaxKind.JsxOpeningElement || node.kind === SyntaxKind.JsxSelfClosingElement;
}

export function isStringLiteralOrJsxExpression(node: Node): node is StringLiteral | JsxExpression {
const kind = node.kind;
return kind === SyntaxKind.StringLiteral
Expand Down
14 changes: 11 additions & 3 deletions src/compiler/visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -426,13 +426,17 @@ namespace ts {
case SyntaxKind.JsxSelfClosingElement:
case SyntaxKind.JsxOpeningElement:
result = reduceNode((<JsxSelfClosingElement | JsxOpeningElement>node).tagName, cbNode, result);
result = reduceNodes((<JsxSelfClosingElement | JsxOpeningElement>node).attributes, cbNodes, result);
result = reduceNode((<JsxSelfClosingElement | JsxOpeningElement>node).attributes, cbNode, result);
break;

case SyntaxKind.JsxClosingElement:
result = reduceNode((<JsxClosingElement>node).tagName, cbNode, result);
break;

case SyntaxKind.JsxAttributes:
result = reduceNodes((<JsxAttributes>node).properties, cbNodes, result);
break;

case SyntaxKind.JsxAttribute:
result = reduceNode((<JsxAttribute>node).name, cbNode, result);
result = reduceNode((<JsxAttribute>node).initializer, cbNode, result);
Expand Down Expand Up @@ -1108,15 +1112,19 @@ namespace ts {
visitNodes((<JsxElement>node).children, visitor, isJsxChild),
visitNode((<JsxElement>node).closingElement, visitor, isJsxClosingElement));

case SyntaxKind.JsxAttributes:
return updateJsxAttributes(<JsxAttributes>node,
visitNodes((<JsxAttributes>node).properties, visitor, isJsxAttributeLike));

case SyntaxKind.JsxSelfClosingElement:
return updateJsxSelfClosingElement(<JsxSelfClosingElement>node,
visitNode((<JsxSelfClosingElement>node).tagName, visitor, isJsxTagNameExpression),
visitNodes((<JsxSelfClosingElement>node).attributes, visitor, isJsxAttributeLike));
visitNode((<JsxSelfClosingElement>node).attributes, visitor, isJsxAttributes));

case SyntaxKind.JsxOpeningElement:
return updateJsxOpeningElement(<JsxOpeningElement>node,
visitNode((<JsxOpeningElement>node).tagName, visitor, isJsxTagNameExpression),
visitNodes((<JsxOpeningElement>node).attributes, visitor, isJsxAttributeLike));
visitNode((<JsxOpeningElement>node).attributes, visitor, isJsxAttributes));

case SyntaxKind.JsxClosingElement:
return updateJsxClosingElement(<JsxClosingElement>node,
Expand Down
Loading