Merge pull request #19249 from uniqueiniquity/jsxFragment

Add support for JSX fragment syntax
This commit is contained in:
Benjamin Lichtman 2017-10-31 11:21:46 -07:00 committed by GitHub
commit 7dfd6c7e20
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 1323 additions and 132 deletions

View file

@ -3296,6 +3296,9 @@ namespace ts {
case SyntaxKind.JsxOpeningElement:
case SyntaxKind.JsxText:
case SyntaxKind.JsxClosingElement:
case SyntaxKind.JsxFragment:
case SyntaxKind.JsxOpeningFragment:
case SyntaxKind.JsxClosingFragment:
case SyntaxKind.JsxAttribute:
case SyntaxKind.JsxAttributes:
case SyntaxKind.JsxSpreadAttribute:

View file

@ -13597,7 +13597,13 @@ namespace ts {
// JSX expression can appear in two position : JSX Element's children or JSX attribute
const jsxAttributes = isJsxAttributeLike(node.parent) ?
node.parent.parent :
node.parent.openingElement.attributes; // node.parent is JsxElement
isJsxElement(node.parent) ?
node.parent.openingElement.attributes :
undefined; // node.parent is JsxFragment with no attributes
if (!jsxAttributes) {
return undefined; // don't check children of a fragment
}
// When we trying to resolve JsxOpeningLikeElement as a stateless function element, we will already give its attributes a contextual type
// which is a type of the parameter of the signature we are trying out.
@ -14177,13 +14183,13 @@ namespace ts {
}
function checkJsxSelfClosingElement(node: JsxSelfClosingElement): Type {
checkJsxOpeningLikeElement(node);
checkJsxOpeningLikeElementOrOpeningFragment(node);
return getJsxGlobalElementType() || anyType;
}
function checkJsxElement(node: JsxElement): Type {
// Check attributes
checkJsxOpeningLikeElement(node.openingElement);
checkJsxOpeningLikeElementOrOpeningFragment(node.openingElement);
// Perform resolution on the closing tag so that rename/go to definition/etc work
if (isJsxIntrinsicIdentifier(node.closingElement.tagName)) {
@ -14196,6 +14202,16 @@ namespace ts {
return getJsxGlobalElementType() || anyType;
}
function checkJsxFragment(node: JsxFragment): Type {
checkJsxOpeningLikeElementOrOpeningFragment(node.openingFragment);
if (compilerOptions.jsx === JsxEmit.React && compilerOptions.jsxFactory) {
error(node, Diagnostics.JSX_fragment_is_not_supported_when_using_jsxFactory);
}
return getJsxGlobalElementType() || anyType;
}
/**
* Returns true iff the JSX element name would be a valid JS identifier, ignoring restrictions about keywords not being identifiers
*/
@ -14859,14 +14875,19 @@ namespace ts {
}
}
function checkJsxOpeningLikeElement(node: JsxOpeningLikeElement) {
checkGrammarJsxElement(node);
function checkJsxOpeningLikeElementOrOpeningFragment(node: JsxOpeningLikeElement | JsxOpeningFragment) {
const isNodeOpeningLikeElement = isJsxOpeningLikeElement(node);
if (isNodeOpeningLikeElement) {
checkGrammarJsxElement(<JsxOpeningLikeElement>node);
}
checkJsxPreconditions(node);
// The reactNamespace/jsxFactory's root symbol should be marked as 'used' so we don't incorrectly elide its import.
// And if there is no reactNamespace/jsxFactory's symbol in scope when targeting React emit, we should issue an error.
const reactRefErr = diagnostics && compilerOptions.jsx === JsxEmit.React ? Diagnostics.Cannot_find_name_0 : undefined;
const reactNamespace = getJsxNamespace();
const reactSym = resolveName(node.tagName, reactNamespace, SymbolFlags.Value, reactRefErr, reactNamespace, /*isUse*/ true);
const reactLocation = isNodeOpeningLikeElement ? (<JsxOpeningLikeElement>node).tagName : node;
const reactSym = resolveName(reactLocation, reactNamespace, SymbolFlags.Value, reactRefErr, reactNamespace, /*isUse*/ true);
if (reactSym) {
// Mark local symbol as referenced here because it might not have been marked
// if jsx emit was not react as there wont be error being emitted
@ -14878,7 +14899,9 @@ namespace ts {
}
}
checkJsxAttributesAssignableToTagNameAttributes(node);
if (isNodeOpeningLikeElement) {
checkJsxAttributesAssignableToTagNameAttributes(<JsxOpeningLikeElement>node);
}
}
/**
@ -18655,6 +18678,8 @@ namespace ts {
return checkJsxElement(<JsxElement>node);
case SyntaxKind.JsxSelfClosingElement:
return checkJsxSelfClosingElement(<JsxSelfClosingElement>node);
case SyntaxKind.JsxFragment:
return checkJsxFragment(<JsxFragment>node);
case SyntaxKind.JsxAttributes:
return checkJsxAttributes(<JsxAttributes>node, checkMode);
case SyntaxKind.JsxOpeningElement:

View file

@ -3615,6 +3615,18 @@
"category": "Error",
"code": 17013
},
"JSX fragment has no corresponding closing tag.": {
"category": "Error",
"code": 17014
},
"Expected corresponding closing tag for JSX fragment.": {
"category": "Error",
"code": 17015
},
"JSX fragment is not supported when using --jsxFactory": {
"category": "Error",
"code":17016
},
"Circularity detected while resolving configuration: {0}": {
"category": "Error",

View file

@ -699,9 +699,11 @@ namespace ts {
case SyntaxKind.JsxText:
return emitJsxText(<JsxText>node);
case SyntaxKind.JsxOpeningElement:
return emitJsxOpeningElement(<JsxOpeningElement>node);
case SyntaxKind.JsxOpeningFragment:
return emitJsxOpeningElementOrFragment(<JsxOpeningElement>node);
case SyntaxKind.JsxClosingElement:
return emitJsxClosingElement(<JsxClosingElement>node);
case SyntaxKind.JsxClosingFragment:
return emitJsxClosingElementOrFragment(<JsxClosingElement>node);
case SyntaxKind.JsxAttribute:
return emitJsxAttribute(<JsxAttribute>node);
case SyntaxKind.JsxAttributes:
@ -836,6 +838,8 @@ namespace ts {
return emitJsxElement(<JsxElement>node);
case SyntaxKind.JsxSelfClosingElement:
return emitJsxSelfClosingElement(<JsxSelfClosingElement>node);
case SyntaxKind.JsxFragment:
return emitJsxFragment(<JsxFragment>node);
// Transformation nodes
case SyntaxKind.PartiallyEmittedExpression:
@ -2060,7 +2064,7 @@ namespace ts {
function emitJsxElement(node: JsxElement) {
emit(node.openingElement);
emitList(node, node.children, ListFormat.JsxElementChildren);
emitList(node, node.children, ListFormat.JsxElementOrFragmentChildren);
emit(node.closingElement);
}
@ -2075,14 +2079,24 @@ namespace ts {
write("/>");
}
function emitJsxOpeningElement(node: JsxOpeningElement) {
function emitJsxFragment(node: JsxFragment) {
emit(node.openingFragment);
emitList(node, node.children, ListFormat.JsxElementOrFragmentChildren);
emit(node.closingFragment);
}
function emitJsxOpeningElementOrFragment(node: JsxOpeningElement | JsxOpeningFragment) {
write("<");
emitJsxTagName(node.tagName);
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);
if (isJsxOpeningElement(node)) {
emitJsxTagName(node.tagName);
// 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) {
write(" ");
emit(node.attributes);
}
}
write(">");
}
@ -2090,9 +2104,11 @@ namespace ts {
writer.writeLiteral(getTextOfNode(node, /*includeTrivia*/ true));
}
function emitJsxClosingElement(node: JsxClosingElement) {
function emitJsxClosingElementOrFragment(node: JsxClosingElement | JsxClosingFragment) {
write("</");
emitJsxTagName(node.tagName);
if (isJsxClosingElement(node)) {
emitJsxTagName(node.tagName);
}
write(">");
}
@ -2611,12 +2627,6 @@ namespace ts {
writer.decreaseIndent();
}
function writeIfAny(nodes: NodeArray<Node>, text: string) {
if (some(nodes)) {
write(text);
}
}
function writeToken(token: SyntaxKind, pos: number, contextNode?: Node) {
return onEmitSourceMapOfToken
? onEmitSourceMapOfToken(contextNode, token, pos, writeTokenText)
@ -3176,7 +3186,7 @@ namespace ts {
EnumMembers = CommaDelimited | Indented | MultiLine,
CaseBlockClauses = Indented | MultiLine,
NamedImportsOrExportsElements = CommaDelimited | SpaceBetweenSiblings | AllowTrailingComma | SingleLine | SpaceBetweenBraces,
JsxElementChildren = SingleLine | NoInterveningComments,
JsxElementOrFragmentChildren = SingleLine | NoInterveningComments,
JsxElementAttributes = SingleLine | SpaceBetweenSiblings | NoInterveningComments,
CaseOrDefaultClauseStatements = Indented | MultiLine | NoTrailingNewLine | OptionalIfEmpty,
HeritageClauseTypes = CommaDelimited | SpaceBetweenSiblings | SingleLine,

View file

@ -2115,6 +2115,22 @@ namespace ts {
: node;
}
export function createJsxFragment(openingFragment: JsxOpeningFragment, children: ReadonlyArray<JsxChild>, closingFragment: JsxClosingFragment) {
const node = <JsxFragment>createSynthesizedNode(SyntaxKind.JsxFragment);
node.openingFragment = openingFragment;
node.children = createNodeArray(children);
node.closingFragment = closingFragment;
return node;
}
export function updateJsxFragment(node: JsxFragment, openingFragment: JsxOpeningFragment, children: ReadonlyArray<JsxChild>, closingFragment: JsxClosingFragment) {
return node.openingFragment !== openingFragment
|| node.children !== children
|| node.closingFragment !== closingFragment
? updateNode(createJsxFragment(openingFragment, children, closingFragment), node)
: node;
}
export function createJsxAttribute(name: Identifier, initializer: StringLiteral | JsxExpression) {
const node = <JsxAttribute>createSynthesizedNode(SyntaxKind.JsxAttribute);
node.name = name;
@ -2951,7 +2967,7 @@ namespace ts {
);
}
function createReactNamespace(reactNamespace: string, parent: JsxOpeningLikeElement) {
function createReactNamespace(reactNamespace: string, parent: JsxOpeningLikeElement | JsxOpeningFragment) {
// To ensure the emit resolver can properly resolve the namespace, we need to
// treat this identifier as if it were a source tree node by clearing the `Synthesized`
// flag and setting a parent node.
@ -2963,7 +2979,7 @@ namespace ts {
return react;
}
function createJsxFactoryExpressionFromEntityName(jsxFactory: EntityName, parent: JsxOpeningLikeElement): Expression {
function createJsxFactoryExpressionFromEntityName(jsxFactory: EntityName, parent: JsxOpeningLikeElement | JsxOpeningFragment): Expression {
if (isQualifiedName(jsxFactory)) {
const left = createJsxFactoryExpressionFromEntityName(jsxFactory.left, parent);
const right = createIdentifier(idText(jsxFactory.right));
@ -2975,7 +2991,7 @@ namespace ts {
}
}
function createJsxFactoryExpression(jsxFactoryEntity: EntityName, reactNamespace: string, parent: JsxOpeningLikeElement): Expression {
function createJsxFactoryExpression(jsxFactoryEntity: EntityName, reactNamespace: string, parent: JsxOpeningLikeElement | JsxOpeningFragment): Expression {
return jsxFactoryEntity ?
createJsxFactoryExpressionFromEntityName(jsxFactoryEntity, parent) :
createPropertyAccess(
@ -3016,6 +3032,37 @@ namespace ts {
);
}
export function createExpressionForJsxFragment(jsxFactoryEntity: EntityName, reactNamespace: string, children: Expression[], parentElement: JsxOpeningFragment, location: TextRange): LeftHandSideExpression {
const tagName = createPropertyAccess(
createReactNamespace(reactNamespace, parentElement),
"Fragment"
);
const argumentsList = [<Expression>tagName];
argumentsList.push(createNull());
if (children && children.length > 0) {
if (children.length > 1) {
for (const child of children) {
child.startsOnNewLine = true;
argumentsList.push(child);
}
}
else {
argumentsList.push(children[0]);
}
}
return setTextRange(
createCall(
createJsxFactoryExpression(jsxFactoryEntity, reactNamespace, parentElement),
/*typeArguments*/ undefined,
argumentsList
),
location
);
}
// Helpers
export function getHelperName(name: string) {

View file

@ -377,6 +377,10 @@ namespace ts {
return visitNode(cbNode, (<JsxElement>node).openingElement) ||
visitNodes(cbNode, cbNodes, (<JsxElement>node).children) ||
visitNode(cbNode, (<JsxElement>node).closingElement);
case SyntaxKind.JsxFragment:
return visitNode(cbNode, (<JsxFragment>node).openingFragment) ||
visitNodes(cbNode, cbNodes, (<JsxFragment>node).children) ||
visitNode(cbNode, (<JsxFragment>node).closingFragment);
case SyntaxKind.JsxSelfClosingElement:
case SyntaxKind.JsxOpeningElement:
return visitNode(cbNode, (<JsxOpeningLikeElement>node).tagName) ||
@ -1423,6 +1427,11 @@ namespace ts {
return tokenIsIdentifierOrKeyword(token());
}
function nextTokenIsIdentifierOrKeywordOrGreaterThan() {
nextToken();
return tokenIsIdentifierOrKeywordOrGreaterThan(token());
}
function isHeritageClauseExtendsOrImplementsKeyword(): boolean {
if (token() === SyntaxKind.ImplementsKeyword ||
token() === SyntaxKind.ExtendsKeyword) {
@ -3802,9 +3811,9 @@ namespace ts {
node.operand = parseLeftHandSideExpressionOrHigher();
return finishNode(node);
}
else if (sourceFile.languageVariant === LanguageVariant.JSX && token() === SyntaxKind.LessThanToken && lookAhead(nextTokenIsIdentifierOrKeyword)) {
else if (sourceFile.languageVariant === LanguageVariant.JSX && token() === SyntaxKind.LessThanToken && lookAhead(nextTokenIsIdentifierOrKeywordOrGreaterThan)) {
// JSXElement is part of primaryExpression
return parseJsxElementOrSelfClosingElement(/*inExpressionContext*/ true);
return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true);
}
const expression = parseLeftHandSideExpressionOrHigher();
@ -3959,14 +3968,14 @@ namespace ts {
}
function parseJsxElementOrSelfClosingElement(inExpressionContext: boolean): JsxElement | JsxSelfClosingElement {
const opening = parseJsxOpeningOrSelfClosingElement(inExpressionContext);
let result: JsxElement | JsxSelfClosingElement;
function parseJsxElementOrSelfClosingElementOrFragment(inExpressionContext: boolean): JsxElement | JsxSelfClosingElement | JsxFragment {
const opening = parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext);
let result: JsxElement | JsxSelfClosingElement | JsxFragment;
if (opening.kind === SyntaxKind.JsxOpeningElement) {
const node = <JsxElement>createNode(SyntaxKind.JsxElement, opening.pos);
node.openingElement = opening;
node.children = parseJsxChildren(node.openingElement.tagName);
node.children = parseJsxChildren(node.openingElement);
node.closingElement = parseJsxClosingElement(inExpressionContext);
if (!tagNamesAreEquivalent(node.openingElement.tagName, node.closingElement.tagName)) {
@ -3975,6 +3984,14 @@ namespace ts {
result = finishNode(node);
}
else if (opening.kind === SyntaxKind.JsxOpeningFragment) {
const node = <JsxFragment>createNode(SyntaxKind.JsxFragment, opening.pos);
node.openingFragment = opening;
node.children = parseJsxChildren(node.openingFragment);
node.closingFragment = parseJsxClosingFragment(inExpressionContext);
result = finishNode(node);
}
else {
Debug.assert(opening.kind === SyntaxKind.JsxSelfClosingElement);
// Nothing else to do for self-closing elements
@ -3989,7 +4006,7 @@ namespace ts {
// Since JSX elements are invalid < operands anyway, this lookahead parse will only occur in error scenarios
// of one sort or another.
if (inExpressionContext && token() === SyntaxKind.LessThanToken) {
const invalidElement = tryParse(() => parseJsxElementOrSelfClosingElement(/*inExpressionContext*/ true));
const invalidElement = tryParse(() => parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true));
if (invalidElement) {
parseErrorAtCurrentToken(Diagnostics.JSX_expressions_must_have_one_parent_element);
const badNode = <BinaryExpression>createNode(SyntaxKind.BinaryExpression, result.pos);
@ -4020,12 +4037,12 @@ namespace ts {
case SyntaxKind.OpenBraceToken:
return parseJsxExpression(/*inExpressionContext*/ false);
case SyntaxKind.LessThanToken:
return parseJsxElementOrSelfClosingElement(/*inExpressionContext*/ false);
return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ false);
}
Debug.fail("Unknown JSX child kind " + token());
}
function parseJsxChildren(openingTagName: LeftHandSideExpression): NodeArray<JsxChild> {
function parseJsxChildren(openingTag: JsxOpeningElement | JsxOpeningFragment): NodeArray<JsxChild> {
const list = [];
const listPos = getNodePos();
const saveParsingContext = parsingContext;
@ -4040,7 +4057,13 @@ namespace ts {
else if (token() === SyntaxKind.EndOfFileToken) {
// If we hit EOF, issue the error at the tag that lacks the closing element
// rather than at the end of the file (which is useless)
parseErrorAtPosition(openingTagName.pos, openingTagName.end - openingTagName.pos, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, openingTagName));
if (isJsxOpeningFragment(openingTag)) {
parseErrorAtPosition(openingTag.pos, openingTag.end - openingTag.pos, Diagnostics.JSX_fragment_has_no_corresponding_closing_tag);
}
else {
const openingTagName = openingTag.tagName;
parseErrorAtPosition(openingTagName.pos, openingTagName.end - openingTagName.pos, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, openingTagName));
}
break;
}
else if (token() === SyntaxKind.ConflictMarkerTrivia) {
@ -4063,11 +4086,17 @@ namespace ts {
return finishNode(jsxAttributes);
}
function parseJsxOpeningOrSelfClosingElement(inExpressionContext: boolean): JsxOpeningElement | JsxSelfClosingElement {
function parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext: boolean): JsxOpeningElement | JsxSelfClosingElement | JsxOpeningFragment {
const fullStart = scanner.getStartPos();
parseExpected(SyntaxKind.LessThanToken);
if (token() === SyntaxKind.GreaterThanToken) {
parseExpected(SyntaxKind.GreaterThanToken);
const node: JsxOpeningFragment = <JsxOpeningFragment>createNode(SyntaxKind.JsxOpeningFragment, fullStart);
return finishNode(node);
}
const tagName = parseJsxElementName();
const attributes = parseJsxAttributes();
@ -4179,6 +4208,23 @@ namespace ts {
return finishNode(node);
}
function parseJsxClosingFragment(inExpressionContext: boolean): JsxClosingFragment {
const node = <JsxClosingFragment>createNode(SyntaxKind.JsxClosingFragment);
parseExpected(SyntaxKind.LessThanSlashToken);
if (tokenIsIdentifierOrKeyword(token())) {
const unexpectedTagName = parseJsxElementName();
parseErrorAtPosition(unexpectedTagName.pos, unexpectedTagName.end - unexpectedTagName.pos, Diagnostics.Expected_corresponding_closing_tag_for_JSX_fragment);
}
if (inExpressionContext) {
parseExpected(SyntaxKind.GreaterThanToken);
}
else {
parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false);
scanJsxText();
}
return finishNode(node);
}
function parseTypeAssertion(): TypeAssertion {
const node = <TypeAssertion>createNode(SyntaxKind.TypeAssertionExpression);
parseExpected(SyntaxKind.LessThanToken);

View file

@ -11,6 +11,11 @@ namespace ts {
return token >= SyntaxKind.Identifier;
}
/* @internal */
export function tokenIsIdentifierOrKeywordOrGreaterThan(token: SyntaxKind): boolean {
return token === SyntaxKind.GreaterThanToken || tokenIsIdentifierOrKeyword(token);
}
export interface Scanner {
getStartPos(): number;
getToken(): SyntaxKind;

View file

@ -41,6 +41,9 @@ namespace ts {
case SyntaxKind.JsxSelfClosingElement:
return visitJsxSelfClosingElement(<JsxSelfClosingElement>node, /*isChild*/ false);
case SyntaxKind.JsxFragment:
return visitJsxFragment(<JsxFragment>node, /*isChild*/ false);
case SyntaxKind.JsxExpression:
return visitJsxExpression(<JsxExpression>node);
@ -63,6 +66,9 @@ namespace ts {
case SyntaxKind.JsxSelfClosingElement:
return visitJsxSelfClosingElement(<JsxSelfClosingElement>node, /*isChild*/ true);
case SyntaxKind.JsxFragment:
return visitJsxFragment(<JsxFragment>node, /*isChild*/ true);
default:
Debug.failBadSyntaxKind(node);
return undefined;
@ -77,6 +83,10 @@ namespace ts {
return visitJsxOpeningLikeElement(node, /*children*/ undefined, isChild, /*location*/ node);
}
function visitJsxFragment(node: JsxFragment, isChild: boolean) {
return visitJsxOpeningFragment(node.openingFragment, node.children, isChild, /*location*/ node);
}
function visitJsxOpeningLikeElement(node: JsxOpeningLikeElement, children: ReadonlyArray<JsxChild>, isChild: boolean, location: TextRange) {
const tagName = getTagName(node);
let objectProperties: Expression;
@ -126,6 +136,22 @@ namespace ts {
return element;
}
function visitJsxOpeningFragment(node: JsxOpeningFragment, children: ReadonlyArray<JsxChild>, isChild: boolean, location: TextRange) {
const element = createExpressionForJsxFragment(
context.getEmitResolver().getJsxFactoryEntity(),
compilerOptions.reactNamespace,
mapDefined(children, transformJsxChildToExpression),
node,
location
);
if (isChild) {
startOnNewLine(element);
}
return element;
}
function transformJsxSpreadAttributeToExpression(node: JsxSpreadAttribute) {
return visitNode(node.expression, visitor, isExpression);
}

View file

@ -328,6 +328,9 @@ namespace ts {
JsxSelfClosingElement,
JsxOpeningElement,
JsxClosingElement,
JsxFragment,
JsxOpeningFragment,
JsxClosingFragment,
JsxAttribute,
JsxAttributes,
JsxSpreadAttribute,
@ -1620,7 +1623,7 @@ namespace ts {
closingElement: JsxClosingElement;
}
/// Either the opening tag in a <Tag>...</Tag> pair, or the lone <Tag /> in a self-closing form
/// 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;
@ -1646,6 +1649,26 @@ namespace ts {
attributes: JsxAttributes;
}
/// A JSX expression of the form <>...</>
export interface JsxFragment extends PrimaryExpression {
kind: SyntaxKind.JsxFragment;
openingFragment: JsxOpeningFragment;
children: NodeArray<JsxChild>;
closingFragment: JsxClosingFragment;
}
/// The opening element of a <>...</> JsxFragment
export interface JsxOpeningFragment extends Expression {
kind: SyntaxKind.JsxOpeningFragment;
parent?: JsxFragment;
}
/// The closing element of a <>...</> JsxFragment
export interface JsxClosingFragment extends Expression {
kind: SyntaxKind.JsxClosingFragment;
parent?: JsxFragment;
}
export interface JsxAttribute extends ObjectLiteralElement {
kind: SyntaxKind.JsxAttribute;
parent?: JsxAttributes;
@ -1679,7 +1702,7 @@ namespace ts {
parent?: JsxElement;
}
export type JsxChild = JsxText | JsxExpression | JsxElement | JsxSelfClosingElement;
export type JsxChild = JsxText | JsxExpression | JsxElement | JsxSelfClosingElement | JsxFragment;
export interface Statement extends Node {
_statementBrand: any;

View file

@ -1262,6 +1262,7 @@ namespace ts {
case SyntaxKind.OmittedExpression:
case SyntaxKind.JsxElement:
case SyntaxKind.JsxSelfClosingElement:
case SyntaxKind.JsxFragment:
case SyntaxKind.YieldExpression:
case SyntaxKind.AwaitExpression:
case SyntaxKind.MetaProperty:
@ -2170,6 +2171,7 @@ namespace ts {
case SyntaxKind.ClassExpression:
case SyntaxKind.JsxElement:
case SyntaxKind.JsxSelfClosingElement:
case SyntaxKind.JsxFragment:
case SyntaxKind.RegularExpressionLiteral:
case SyntaxKind.NoSubstitutionTemplateLiteral:
case SyntaxKind.TemplateExpression:
@ -4794,6 +4796,18 @@ namespace ts {
return node.kind === SyntaxKind.JsxClosingElement;
}
export function isJsxFragment(node: Node): node is JsxFragment {
return node.kind === SyntaxKind.JsxFragment;
}
export function isJsxOpeningFragment(node: Node): node is JsxOpeningFragment {
return node.kind === SyntaxKind.JsxOpeningFragment;
}
export function isJsxClosingFragment(node: Node): node is JsxClosingFragment {
return node.kind === SyntaxKind.JsxClosingFragment;
}
export function isJsxAttribute(node: Node): node is JsxAttribute {
return node.kind === SyntaxKind.JsxAttribute;
}
@ -5319,6 +5333,7 @@ namespace ts {
case SyntaxKind.CallExpression:
case SyntaxKind.JsxElement:
case SyntaxKind.JsxSelfClosingElement:
case SyntaxKind.JsxFragment:
case SyntaxKind.TaggedTemplateExpression:
case SyntaxKind.ArrayLiteralExpression:
case SyntaxKind.ParenthesizedExpression:
@ -5640,7 +5655,8 @@ namespace ts {
return kind === SyntaxKind.JsxElement
|| kind === SyntaxKind.JsxExpression
|| kind === SyntaxKind.JsxSelfClosingElement
|| kind === SyntaxKind.JsxText;
|| kind === SyntaxKind.JsxText
|| kind === SyntaxKind.JsxFragment;
}
/* @internal */

View file

@ -819,6 +819,12 @@ namespace ts {
return updateJsxClosingElement(<JsxClosingElement>node,
visitNode((<JsxClosingElement>node).tagName, visitor, isJsxTagNameExpression));
case SyntaxKind.JsxFragment:
return updateJsxFragment(<JsxFragment>node,
visitNode((<JsxFragment>node).openingFragment, visitor, isJsxOpeningFragment),
nodesVisitor((<JsxFragment>node).children, visitor, isJsxChild),
visitNode((<JsxFragment>node).closingFragment, visitor, isJsxClosingFragment));
case SyntaxKind.JsxAttribute:
return updateJsxAttribute(<JsxAttribute>node,
visitNode((<JsxAttribute>node).name, visitor, isIdentifier),
@ -1334,6 +1340,12 @@ namespace ts {
result = reduceNode((<JsxElement>node).closingElement, cbNode, result);
break;
case SyntaxKind.JsxFragment:
result = reduceNode((<JsxFragment>node).openingFragment, cbNode, result);
result = reduceLeft((<JsxFragment>node).children, cbNode, result);
result = reduceNode((<JsxFragment>node).closingFragment, cbNode, result);
break;
case SyntaxKind.JsxSelfClosingElement:
case SyntaxKind.JsxOpeningElement:
result = reduceNode((<JsxSelfClosingElement | JsxOpeningElement>node).tagName, cbNode, result);

View file

@ -313,46 +313,49 @@ declare namespace ts {
JsxSelfClosingElement = 250,
JsxOpeningElement = 251,
JsxClosingElement = 252,
JsxAttribute = 253,
JsxAttributes = 254,
JsxSpreadAttribute = 255,
JsxExpression = 256,
CaseClause = 257,
DefaultClause = 258,
HeritageClause = 259,
CatchClause = 260,
PropertyAssignment = 261,
ShorthandPropertyAssignment = 262,
SpreadAssignment = 263,
EnumMember = 264,
SourceFile = 265,
Bundle = 266,
JSDocTypeExpression = 267,
JSDocAllType = 268,
JSDocUnknownType = 269,
JSDocNullableType = 270,
JSDocNonNullableType = 271,
JSDocOptionalType = 272,
JSDocFunctionType = 273,
JSDocVariadicType = 274,
JSDocComment = 275,
JSDocTypeLiteral = 276,
JSDocTag = 277,
JSDocAugmentsTag = 278,
JSDocClassTag = 279,
JSDocParameterTag = 280,
JSDocReturnTag = 281,
JSDocTypeTag = 282,
JSDocTemplateTag = 283,
JSDocTypedefTag = 284,
JSDocPropertyTag = 285,
SyntaxList = 286,
NotEmittedStatement = 287,
PartiallyEmittedExpression = 288,
CommaListExpression = 289,
MergeDeclarationMarker = 290,
EndOfDeclarationMarker = 291,
Count = 292,
JsxFragment = 253,
JsxOpeningFragment = 254,
JsxClosingFragment = 255,
JsxAttribute = 256,
JsxAttributes = 257,
JsxSpreadAttribute = 258,
JsxExpression = 259,
CaseClause = 260,
DefaultClause = 261,
HeritageClause = 262,
CatchClause = 263,
PropertyAssignment = 264,
ShorthandPropertyAssignment = 265,
SpreadAssignment = 266,
EnumMember = 267,
SourceFile = 268,
Bundle = 269,
JSDocTypeExpression = 270,
JSDocAllType = 271,
JSDocUnknownType = 272,
JSDocNullableType = 273,
JSDocNonNullableType = 274,
JSDocOptionalType = 275,
JSDocFunctionType = 276,
JSDocVariadicType = 277,
JSDocComment = 278,
JSDocTypeLiteral = 279,
JSDocTag = 280,
JSDocAugmentsTag = 281,
JSDocClassTag = 282,
JSDocParameterTag = 283,
JSDocReturnTag = 284,
JSDocTypeTag = 285,
JSDocTemplateTag = 286,
JSDocTypedefTag = 287,
JSDocPropertyTag = 288,
SyntaxList = 289,
NotEmittedStatement = 290,
PartiallyEmittedExpression = 291,
CommaListExpression = 292,
MergeDeclarationMarker = 293,
EndOfDeclarationMarker = 294,
Count = 295,
FirstAssignment = 58,
LastAssignment = 70,
FirstCompoundAssignment = 59,
@ -378,10 +381,10 @@ declare namespace ts {
FirstBinaryOperator = 27,
LastBinaryOperator = 70,
FirstNode = 143,
FirstJSDocNode = 267,
LastJSDocNode = 285,
FirstJSDocTagNode = 277,
LastJSDocTagNode = 285,
FirstJSDocNode = 270,
LastJSDocNode = 288,
FirstJSDocTagNode = 280,
LastJSDocTagNode = 288,
}
enum NodeFlags {
None = 0,
@ -1061,6 +1064,20 @@ declare namespace ts {
tagName: JsxTagNameExpression;
attributes: JsxAttributes;
}
interface JsxFragment extends PrimaryExpression {
kind: SyntaxKind.JsxFragment;
openingFragment: JsxOpeningFragment;
children: NodeArray<JsxChild>;
closingFragment: JsxClosingFragment;
}
interface JsxOpeningFragment extends Expression {
kind: SyntaxKind.JsxOpeningFragment;
parent?: JsxFragment;
}
interface JsxClosingFragment extends Expression {
kind: SyntaxKind.JsxClosingFragment;
parent?: JsxFragment;
}
interface JsxAttribute extends ObjectLiteralElement {
kind: SyntaxKind.JsxAttribute;
parent?: JsxAttributes;
@ -1088,7 +1105,7 @@ declare namespace ts {
containsOnlyWhiteSpaces: boolean;
parent?: JsxElement;
}
type JsxChild = JsxText | JsxExpression | JsxElement | JsxSelfClosingElement;
type JsxChild = JsxText | JsxExpression | JsxElement | JsxSelfClosingElement | JsxFragment;
interface Statement extends Node {
_statementBrand: any;
}
@ -3002,6 +3019,9 @@ declare namespace ts {
function isJsxSelfClosingElement(node: Node): node is JsxSelfClosingElement;
function isJsxOpeningElement(node: Node): node is JsxOpeningElement;
function isJsxClosingElement(node: Node): node is JsxClosingElement;
function isJsxFragment(node: Node): node is JsxFragment;
function isJsxOpeningFragment(node: Node): node is JsxOpeningFragment;
function isJsxClosingFragment(node: Node): node is JsxClosingFragment;
function isJsxAttribute(node: Node): node is JsxAttribute;
function isJsxAttributes(node: Node): node is JsxAttributes;
function isJsxSpreadAttribute(node: Node): node is JsxSpreadAttribute;
@ -3501,6 +3521,8 @@ declare namespace ts {
function updateJsxOpeningElement(node: JsxOpeningElement, tagName: JsxTagNameExpression, attributes: JsxAttributes): JsxOpeningElement;
function createJsxClosingElement(tagName: JsxTagNameExpression): JsxClosingElement;
function updateJsxClosingElement(node: JsxClosingElement, tagName: JsxTagNameExpression): JsxClosingElement;
function createJsxFragment(openingFragment: JsxOpeningFragment, children: ReadonlyArray<JsxChild>, closingFragment: JsxClosingFragment): JsxFragment;
function updateJsxFragment(node: JsxFragment, openingFragment: JsxOpeningFragment, children: ReadonlyArray<JsxChild>, closingFragment: JsxClosingFragment): JsxFragment;
function createJsxAttribute(name: Identifier, initializer: StringLiteral | JsxExpression): JsxAttribute;
function updateJsxAttribute(node: JsxAttribute, name: Identifier, initializer: StringLiteral | JsxExpression): JsxAttribute;
function createJsxAttributes(properties: ReadonlyArray<JsxAttributeLike>): JsxAttributes;

View file

@ -313,46 +313,49 @@ declare namespace ts {
JsxSelfClosingElement = 250,
JsxOpeningElement = 251,
JsxClosingElement = 252,
JsxAttribute = 253,
JsxAttributes = 254,
JsxSpreadAttribute = 255,
JsxExpression = 256,
CaseClause = 257,
DefaultClause = 258,
HeritageClause = 259,
CatchClause = 260,
PropertyAssignment = 261,
ShorthandPropertyAssignment = 262,
SpreadAssignment = 263,
EnumMember = 264,
SourceFile = 265,
Bundle = 266,
JSDocTypeExpression = 267,
JSDocAllType = 268,
JSDocUnknownType = 269,
JSDocNullableType = 270,
JSDocNonNullableType = 271,
JSDocOptionalType = 272,
JSDocFunctionType = 273,
JSDocVariadicType = 274,
JSDocComment = 275,
JSDocTypeLiteral = 276,
JSDocTag = 277,
JSDocAugmentsTag = 278,
JSDocClassTag = 279,
JSDocParameterTag = 280,
JSDocReturnTag = 281,
JSDocTypeTag = 282,
JSDocTemplateTag = 283,
JSDocTypedefTag = 284,
JSDocPropertyTag = 285,
SyntaxList = 286,
NotEmittedStatement = 287,
PartiallyEmittedExpression = 288,
CommaListExpression = 289,
MergeDeclarationMarker = 290,
EndOfDeclarationMarker = 291,
Count = 292,
JsxFragment = 253,
JsxOpeningFragment = 254,
JsxClosingFragment = 255,
JsxAttribute = 256,
JsxAttributes = 257,
JsxSpreadAttribute = 258,
JsxExpression = 259,
CaseClause = 260,
DefaultClause = 261,
HeritageClause = 262,
CatchClause = 263,
PropertyAssignment = 264,
ShorthandPropertyAssignment = 265,
SpreadAssignment = 266,
EnumMember = 267,
SourceFile = 268,
Bundle = 269,
JSDocTypeExpression = 270,
JSDocAllType = 271,
JSDocUnknownType = 272,
JSDocNullableType = 273,
JSDocNonNullableType = 274,
JSDocOptionalType = 275,
JSDocFunctionType = 276,
JSDocVariadicType = 277,
JSDocComment = 278,
JSDocTypeLiteral = 279,
JSDocTag = 280,
JSDocAugmentsTag = 281,
JSDocClassTag = 282,
JSDocParameterTag = 283,
JSDocReturnTag = 284,
JSDocTypeTag = 285,
JSDocTemplateTag = 286,
JSDocTypedefTag = 287,
JSDocPropertyTag = 288,
SyntaxList = 289,
NotEmittedStatement = 290,
PartiallyEmittedExpression = 291,
CommaListExpression = 292,
MergeDeclarationMarker = 293,
EndOfDeclarationMarker = 294,
Count = 295,
FirstAssignment = 58,
LastAssignment = 70,
FirstCompoundAssignment = 59,
@ -378,10 +381,10 @@ declare namespace ts {
FirstBinaryOperator = 27,
LastBinaryOperator = 70,
FirstNode = 143,
FirstJSDocNode = 267,
LastJSDocNode = 285,
FirstJSDocTagNode = 277,
LastJSDocTagNode = 285,
FirstJSDocNode = 270,
LastJSDocNode = 288,
FirstJSDocTagNode = 280,
LastJSDocTagNode = 288,
}
enum NodeFlags {
None = 0,
@ -1061,6 +1064,20 @@ declare namespace ts {
tagName: JsxTagNameExpression;
attributes: JsxAttributes;
}
interface JsxFragment extends PrimaryExpression {
kind: SyntaxKind.JsxFragment;
openingFragment: JsxOpeningFragment;
children: NodeArray<JsxChild>;
closingFragment: JsxClosingFragment;
}
interface JsxOpeningFragment extends Expression {
kind: SyntaxKind.JsxOpeningFragment;
parent?: JsxFragment;
}
interface JsxClosingFragment extends Expression {
kind: SyntaxKind.JsxClosingFragment;
parent?: JsxFragment;
}
interface JsxAttribute extends ObjectLiteralElement {
kind: SyntaxKind.JsxAttribute;
parent?: JsxAttributes;
@ -1088,7 +1105,7 @@ declare namespace ts {
containsOnlyWhiteSpaces: boolean;
parent?: JsxElement;
}
type JsxChild = JsxText | JsxExpression | JsxElement | JsxSelfClosingElement;
type JsxChild = JsxText | JsxExpression | JsxElement | JsxSelfClosingElement | JsxFragment;
interface Statement extends Node {
_statementBrand: any;
}
@ -3057,6 +3074,9 @@ declare namespace ts {
function isJsxSelfClosingElement(node: Node): node is JsxSelfClosingElement;
function isJsxOpeningElement(node: Node): node is JsxOpeningElement;
function isJsxClosingElement(node: Node): node is JsxClosingElement;
function isJsxFragment(node: Node): node is JsxFragment;
function isJsxOpeningFragment(node: Node): node is JsxOpeningFragment;
function isJsxClosingFragment(node: Node): node is JsxClosingFragment;
function isJsxAttribute(node: Node): node is JsxAttribute;
function isJsxAttributes(node: Node): node is JsxAttributes;
function isJsxSpreadAttribute(node: Node): node is JsxSpreadAttribute;
@ -3448,6 +3468,8 @@ declare namespace ts {
function updateJsxOpeningElement(node: JsxOpeningElement, tagName: JsxTagNameExpression, attributes: JsxAttributes): JsxOpeningElement;
function createJsxClosingElement(tagName: JsxTagNameExpression): JsxClosingElement;
function updateJsxClosingElement(node: JsxClosingElement, tagName: JsxTagNameExpression): JsxClosingElement;
function createJsxFragment(openingFragment: JsxOpeningFragment, children: ReadonlyArray<JsxChild>, closingFragment: JsxClosingFragment): JsxFragment;
function updateJsxFragment(node: JsxFragment, openingFragment: JsxOpeningFragment, children: ReadonlyArray<JsxChild>, closingFragment: JsxClosingFragment): JsxFragment;
function createJsxAttribute(name: Identifier, initializer: StringLiteral | JsxExpression): JsxAttribute;
function updateJsxAttribute(node: JsxAttribute, name: Identifier, initializer: StringLiteral | JsxExpression): JsxAttribute;
function createJsxAttributes(properties: ReadonlyArray<JsxAttributeLike>): JsxAttributes;

View file

@ -0,0 +1,56 @@
tests/cases/conformance/jsx/file.tsx(42,27): error TS2322: Type '{ a: 10; b: "hi"; children: Element[]; }' is not assignable to type 'IntrinsicAttributes & SingleChildProp'.
Type '{ a: 10; b: "hi"; children: Element[]; }' is not assignable to type 'SingleChildProp'.
Types of property 'children' are incompatible.
Type 'Element[]' is not assignable to type 'Element'.
Property 'type' is missing in type 'Element[]'.
==== tests/cases/conformance/jsx/file.tsx (1 errors) ====
import React = require('react');
interface Prop {
a: number,
b: string,
children: JSX.Element | JSX.Element[];
}
class Button extends React.Component<any, any> {
render() {
return (<div>My Button</div>)
}
}
function AnotherButton(p: any) {
return <h1>Just Another Button</h1>;
}
function Comp(p: Prop) {
return <div>{p.b}</div>;
}
// OK
let k1 = <Comp a={10} b="hi"><></><Button /><AnotherButton /></Comp>;
let k2 = <Comp a={10} b="hi"><><Button /></><AnotherButton /></Comp>;
let k3 = <Comp a={10} b="hi"><><Button /><AnotherButton /></></Comp>;
interface SingleChildProp {
a: number,
b: string,
children: JSX.Element;
}
function SingleChildComp(p: SingleChildProp) {
return <div>{p.b}</div>;
}
// OK
let k4 = <SingleChildComp a={10} b="hi"><><Button /><AnotherButton /></></SingleChildComp>;
// Error
let k5 = <SingleChildComp a={10} b="hi"><></><Button /><AnotherButton /></SingleChildComp>;
~~~~~~~~~~~~~
!!! error TS2322: Type '{ a: 10; b: "hi"; children: Element[]; }' is not assignable to type 'IntrinsicAttributes & SingleChildProp'.
!!! error TS2322: Type '{ a: 10; b: "hi"; children: Element[]; }' is not assignable to type 'SingleChildProp'.
!!! error TS2322: Types of property 'children' are incompatible.
!!! error TS2322: Type 'Element[]' is not assignable to type 'Element'.
!!! error TS2322: Property 'type' is missing in type 'Element[]'.

View file

@ -0,0 +1,85 @@
//// [file.tsx]
import React = require('react');
interface Prop {
a: number,
b: string,
children: JSX.Element | JSX.Element[];
}
class Button extends React.Component<any, any> {
render() {
return (<div>My Button</div>)
}
}
function AnotherButton(p: any) {
return <h1>Just Another Button</h1>;
}
function Comp(p: Prop) {
return <div>{p.b}</div>;
}
// OK
let k1 = <Comp a={10} b="hi"><></><Button /><AnotherButton /></Comp>;
let k2 = <Comp a={10} b="hi"><><Button /></><AnotherButton /></Comp>;
let k3 = <Comp a={10} b="hi"><><Button /><AnotherButton /></></Comp>;
interface SingleChildProp {
a: number,
b: string,
children: JSX.Element;
}
function SingleChildComp(p: SingleChildProp) {
return <div>{p.b}</div>;
}
// OK
let k4 = <SingleChildComp a={10} b="hi"><><Button /><AnotherButton /></></SingleChildComp>;
// Error
let k5 = <SingleChildComp a={10} b="hi"><></><Button /><AnotherButton /></SingleChildComp>;
//// [file.jsx]
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
exports.__esModule = true;
var React = require("react");
var Button = /** @class */ (function (_super) {
__extends(Button, _super);
function Button() {
return _super !== null && _super.apply(this, arguments) || this;
}
Button.prototype.render = function () {
return (<div>My Button</div>);
};
return Button;
}(React.Component));
function AnotherButton(p) {
return <h1>Just Another Button</h1>;
}
function Comp(p) {
return <div>{p.b}</div>;
}
// OK
var k1 = <Comp a={10} b="hi"><></><Button /><AnotherButton /></Comp>;
var k2 = <Comp a={10} b="hi"><><Button /></><AnotherButton /></Comp>;
var k3 = <Comp a={10} b="hi"><><Button /><AnotherButton /></></Comp>;
function SingleChildComp(p) {
return <div>{p.b}</div>;
}
// OK
var k4 = <SingleChildComp a={10} b="hi"><><Button /><AnotherButton /></></SingleChildComp>;
// Error
var k5 = <SingleChildComp a={10} b="hi"><></><Button /><AnotherButton /></SingleChildComp>;

View file

@ -0,0 +1,134 @@
=== tests/cases/conformance/jsx/file.tsx ===
import React = require('react');
>React : Symbol(React, Decl(file.tsx, 0, 0))
interface Prop {
>Prop : Symbol(Prop, Decl(file.tsx, 0, 32))
a: number,
>a : Symbol(Prop.a, Decl(file.tsx, 2, 16))
b: string,
>b : Symbol(Prop.b, Decl(file.tsx, 3, 14))
children: JSX.Element | JSX.Element[];
>children : Symbol(Prop.children, Decl(file.tsx, 4, 14))
>JSX : Symbol(JSX, Decl(react.d.ts, 2353, 1))
>Element : Symbol(JSX.Element, Decl(react.d.ts, 2356, 27))
>JSX : Symbol(JSX, Decl(react.d.ts, 2353, 1))
>Element : Symbol(JSX.Element, Decl(react.d.ts, 2356, 27))
}
class Button extends React.Component<any, any> {
>Button : Symbol(Button, Decl(file.tsx, 6, 1))
>React.Component : Symbol(React.Component, Decl(react.d.ts, 158, 55), Decl(react.d.ts, 161, 66))
>React : Symbol(React, Decl(file.tsx, 0, 0))
>Component : Symbol(React.Component, Decl(react.d.ts, 158, 55), Decl(react.d.ts, 161, 66))
render() {
>render : Symbol(Button.render, Decl(file.tsx, 8, 48))
return (<div>My Button</div>)
>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45))
>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45))
}
}
function AnotherButton(p: any) {
>AnotherButton : Symbol(AnotherButton, Decl(file.tsx, 12, 1))
>p : Symbol(p, Decl(file.tsx, 14, 23))
return <h1>Just Another Button</h1>;
>h1 : Symbol(JSX.IntrinsicElements.h1, Decl(react.d.ts, 2410, 47))
>h1 : Symbol(JSX.IntrinsicElements.h1, Decl(react.d.ts, 2410, 47))
}
function Comp(p: Prop) {
>Comp : Symbol(Comp, Decl(file.tsx, 16, 1))
>p : Symbol(p, Decl(file.tsx, 18, 14))
>Prop : Symbol(Prop, Decl(file.tsx, 0, 32))
return <div>{p.b}</div>;
>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45))
>p.b : Symbol(Prop.b, Decl(file.tsx, 3, 14))
>p : Symbol(p, Decl(file.tsx, 18, 14))
>b : Symbol(Prop.b, Decl(file.tsx, 3, 14))
>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45))
}
// OK
let k1 = <Comp a={10} b="hi"><></><Button /><AnotherButton /></Comp>;
>k1 : Symbol(k1, Decl(file.tsx, 23, 3))
>Comp : Symbol(Comp, Decl(file.tsx, 16, 1))
>a : Symbol(a, Decl(file.tsx, 23, 14))
>b : Symbol(b, Decl(file.tsx, 23, 21))
>Button : Symbol(Button, Decl(file.tsx, 6, 1))
>AnotherButton : Symbol(AnotherButton, Decl(file.tsx, 12, 1))
>Comp : Symbol(Comp, Decl(file.tsx, 16, 1))
let k2 = <Comp a={10} b="hi"><><Button /></><AnotherButton /></Comp>;
>k2 : Symbol(k2, Decl(file.tsx, 24, 3))
>Comp : Symbol(Comp, Decl(file.tsx, 16, 1))
>a : Symbol(a, Decl(file.tsx, 24, 14))
>b : Symbol(b, Decl(file.tsx, 24, 21))
>Button : Symbol(Button, Decl(file.tsx, 6, 1))
>AnotherButton : Symbol(AnotherButton, Decl(file.tsx, 12, 1))
>Comp : Symbol(Comp, Decl(file.tsx, 16, 1))
let k3 = <Comp a={10} b="hi"><><Button /><AnotherButton /></></Comp>;
>k3 : Symbol(k3, Decl(file.tsx, 25, 3))
>Comp : Symbol(Comp, Decl(file.tsx, 16, 1))
>a : Symbol(a, Decl(file.tsx, 25, 14))
>b : Symbol(b, Decl(file.tsx, 25, 21))
>Button : Symbol(Button, Decl(file.tsx, 6, 1))
>AnotherButton : Symbol(AnotherButton, Decl(file.tsx, 12, 1))
>Comp : Symbol(Comp, Decl(file.tsx, 16, 1))
interface SingleChildProp {
>SingleChildProp : Symbol(SingleChildProp, Decl(file.tsx, 25, 69))
a: number,
>a : Symbol(SingleChildProp.a, Decl(file.tsx, 27, 27))
b: string,
>b : Symbol(SingleChildProp.b, Decl(file.tsx, 28, 14))
children: JSX.Element;
>children : Symbol(SingleChildProp.children, Decl(file.tsx, 29, 14))
>JSX : Symbol(JSX, Decl(react.d.ts, 2353, 1))
>Element : Symbol(JSX.Element, Decl(react.d.ts, 2356, 27))
}
function SingleChildComp(p: SingleChildProp) {
>SingleChildComp : Symbol(SingleChildComp, Decl(file.tsx, 31, 1))
>p : Symbol(p, Decl(file.tsx, 33, 25))
>SingleChildProp : Symbol(SingleChildProp, Decl(file.tsx, 25, 69))
return <div>{p.b}</div>;
>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45))
>p.b : Symbol(SingleChildProp.b, Decl(file.tsx, 28, 14))
>p : Symbol(p, Decl(file.tsx, 33, 25))
>b : Symbol(SingleChildProp.b, Decl(file.tsx, 28, 14))
>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45))
}
// OK
let k4 = <SingleChildComp a={10} b="hi"><><Button /><AnotherButton /></></SingleChildComp>;
>k4 : Symbol(k4, Decl(file.tsx, 38, 3))
>SingleChildComp : Symbol(SingleChildComp, Decl(file.tsx, 31, 1))
>a : Symbol(a, Decl(file.tsx, 38, 25))
>b : Symbol(b, Decl(file.tsx, 38, 32))
>Button : Symbol(Button, Decl(file.tsx, 6, 1))
>AnotherButton : Symbol(AnotherButton, Decl(file.tsx, 12, 1))
>SingleChildComp : Symbol(SingleChildComp, Decl(file.tsx, 31, 1))
// Error
let k5 = <SingleChildComp a={10} b="hi"><></><Button /><AnotherButton /></SingleChildComp>;
>k5 : Symbol(k5, Decl(file.tsx, 41, 3))
>SingleChildComp : Symbol(SingleChildComp, Decl(file.tsx, 31, 1))
>a : Symbol(a, Decl(file.tsx, 41, 25))
>b : Symbol(b, Decl(file.tsx, 41, 32))
>Button : Symbol(Button, Decl(file.tsx, 6, 1))
>AnotherButton : Symbol(AnotherButton, Decl(file.tsx, 12, 1))
>SingleChildComp : Symbol(SingleChildComp, Decl(file.tsx, 31, 1))

View file

@ -0,0 +1,164 @@
=== tests/cases/conformance/jsx/file.tsx ===
import React = require('react');
>React : typeof React
interface Prop {
>Prop : Prop
a: number,
>a : number
b: string,
>b : string
children: JSX.Element | JSX.Element[];
>children : JSX.Element | JSX.Element[]
>JSX : any
>Element : JSX.Element
>JSX : any
>Element : JSX.Element
}
class Button extends React.Component<any, any> {
>Button : Button
>React.Component : React.Component<any, any>
>React : typeof React
>Component : typeof React.Component
render() {
>render : () => JSX.Element
return (<div>My Button</div>)
>(<div>My Button</div>) : JSX.Element
><div>My Button</div> : JSX.Element
>div : any
>div : any
}
}
function AnotherButton(p: any) {
>AnotherButton : (p: any) => JSX.Element
>p : any
return <h1>Just Another Button</h1>;
><h1>Just Another Button</h1> : JSX.Element
>h1 : any
>h1 : any
}
function Comp(p: Prop) {
>Comp : (p: Prop) => JSX.Element
>p : Prop
>Prop : Prop
return <div>{p.b}</div>;
><div>{p.b}</div> : JSX.Element
>div : any
>p.b : string
>p : Prop
>b : string
>div : any
}
// OK
let k1 = <Comp a={10} b="hi"><></><Button /><AnotherButton /></Comp>;
>k1 : JSX.Element
><Comp a={10} b="hi"><></><Button /><AnotherButton /></Comp> : JSX.Element
>Comp : (p: Prop) => JSX.Element
>a : number
>10 : 10
>b : string
><></> : JSX.Element
><Button /> : JSX.Element
>Button : typeof Button
><AnotherButton /> : JSX.Element
>AnotherButton : (p: any) => JSX.Element
>Comp : (p: Prop) => JSX.Element
let k2 = <Comp a={10} b="hi"><><Button /></><AnotherButton /></Comp>;
>k2 : JSX.Element
><Comp a={10} b="hi"><><Button /></><AnotherButton /></Comp> : JSX.Element
>Comp : (p: Prop) => JSX.Element
>a : number
>10 : 10
>b : string
><><Button /></> : JSX.Element
><Button /> : JSX.Element
>Button : typeof Button
><AnotherButton /> : JSX.Element
>AnotherButton : (p: any) => JSX.Element
>Comp : (p: Prop) => JSX.Element
let k3 = <Comp a={10} b="hi"><><Button /><AnotherButton /></></Comp>;
>k3 : JSX.Element
><Comp a={10} b="hi"><><Button /><AnotherButton /></></Comp> : JSX.Element
>Comp : (p: Prop) => JSX.Element
>a : number
>10 : 10
>b : string
><><Button /><AnotherButton /></> : JSX.Element
><Button /> : JSX.Element
>Button : typeof Button
><AnotherButton /> : JSX.Element
>AnotherButton : (p: any) => JSX.Element
>Comp : (p: Prop) => JSX.Element
interface SingleChildProp {
>SingleChildProp : SingleChildProp
a: number,
>a : number
b: string,
>b : string
children: JSX.Element;
>children : JSX.Element
>JSX : any
>Element : JSX.Element
}
function SingleChildComp(p: SingleChildProp) {
>SingleChildComp : (p: SingleChildProp) => JSX.Element
>p : SingleChildProp
>SingleChildProp : SingleChildProp
return <div>{p.b}</div>;
><div>{p.b}</div> : JSX.Element
>div : any
>p.b : string
>p : SingleChildProp
>b : string
>div : any
}
// OK
let k4 = <SingleChildComp a={10} b="hi"><><Button /><AnotherButton /></></SingleChildComp>;
>k4 : JSX.Element
><SingleChildComp a={10} b="hi"><><Button /><AnotherButton /></></SingleChildComp> : JSX.Element
>SingleChildComp : (p: SingleChildProp) => JSX.Element
>a : number
>10 : 10
>b : string
><><Button /><AnotherButton /></> : JSX.Element
><Button /> : JSX.Element
>Button : typeof Button
><AnotherButton /> : JSX.Element
>AnotherButton : (p: any) => JSX.Element
>SingleChildComp : (p: SingleChildProp) => JSX.Element
// Error
let k5 = <SingleChildComp a={10} b="hi"><></><Button /><AnotherButton /></SingleChildComp>;
>k5 : JSX.Element
><SingleChildComp a={10} b="hi"><></><Button /><AnotherButton /></SingleChildComp> : JSX.Element
>SingleChildComp : (p: SingleChildProp) => JSX.Element
>a : number
>10 : 10
>b : string
><></> : JSX.Element
><Button /> : JSX.Element
>Button : typeof Button
><AnotherButton /> : JSX.Element
>AnotherButton : (p: any) => JSX.Element
>SingleChildComp : (p: SingleChildProp) => JSX.Element

View file

@ -0,0 +1,13 @@
tests/cases/compiler/jsxFactoryAndFragment.tsx(3,1): error TS17016: JSX fragment is not supported when using --jsxFactory
tests/cases/compiler/jsxFactoryAndFragment.tsx(4,1): error TS17016: JSX fragment is not supported when using --jsxFactory
==== tests/cases/compiler/jsxFactoryAndFragment.tsx (2 errors) ====
declare var h: any;
<></>;
~~~~~
!!! error TS17016: JSX fragment is not supported when using --jsxFactory
<><span>1</span><><span>2.1</span><span>2.2</span></></>;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS17016: JSX fragment is not supported when using --jsxFactory

View file

@ -0,0 +1,13 @@
//// [jsxFactoryAndFragment.tsx]
declare var h: any;
<></>;
<><span>1</span><><span>2.1</span><span>2.2</span></></>;
//// [jsxFactoryAndFragment.js]
h(React.Fragment, null);
h(React.Fragment, null,
h("span", null, "1"),
h(React.Fragment, null,
h("span", null, "2.1"),
h("span", null, "2.2")));

View file

@ -0,0 +1,13 @@
=== tests/cases/compiler/jsxFactoryAndFragment.tsx ===
declare var h: any;
>h : Symbol(h, Decl(jsxFactoryAndFragment.tsx, 0, 11))
<></>;
<><span>1</span><><span>2.1</span><span>2.2</span></></>;
>span : Symbol(unknown)
>span : Symbol(unknown)
>span : Symbol(unknown)
>span : Symbol(unknown)
>span : Symbol(unknown)
>span : Symbol(unknown)

View file

@ -0,0 +1,20 @@
=== tests/cases/compiler/jsxFactoryAndFragment.tsx ===
declare var h: any;
>h : any
<></>;
><></> : any
<><span>1</span><><span>2.1</span><span>2.2</span></></>;
><><span>1</span><><span>2.1</span><span>2.2</span></></> : any
><span>1</span> : any
>span : any
>span : any
><><span>2.1</span><span>2.2</span></> : any
><span>2.1</span> : any
>span : any
>span : any
><span>2.2</span> : any
>span : any
>span : any

View file

@ -0,0 +1,25 @@
tests/cases/conformance/jsx/file.tsx(9,7): error TS17015: Expected corresponding closing tag for JSX fragment.
tests/cases/conformance/jsx/file.tsx(9,11): error TS17014: JSX fragment has no corresponding closing tag.
tests/cases/conformance/jsx/file.tsx(11,17): error TS1005: '</' expected.
==== tests/cases/conformance/jsx/file.tsx (3 errors) ====
declare module JSX {
interface Element { }
interface IntrinsicElements {
[s: string]: any;
}
}
declare var React: any;
<>hi</div> // Error
~~~
!!! error TS17015: Expected corresponding closing tag for JSX fragment.
~~~~~~~~~
<>eof // Error
~~
!!! error TS17014: JSX fragment has no corresponding closing tag.
!!! error TS1005: '</' expected.

View file

@ -0,0 +1,17 @@
//// [file.tsx]
declare module JSX {
interface Element { }
interface IntrinsicElements {
[s: string]: any;
}
}
declare var React: any;
<>hi</div> // Error
<>eof // Error
//// [file.js]
React.createElement(React.Fragment, null, "hi") // Error
, // Error
React.createElement(React.Fragment, null, "eof // Error");

View file

@ -0,0 +1,20 @@
=== tests/cases/conformance/jsx/file.tsx ===
declare module JSX {
>JSX : Symbol(JSX, Decl(file.tsx, 0, 0))
interface Element { }
>Element : Symbol(Element, Decl(file.tsx, 0, 20))
interface IntrinsicElements {
>IntrinsicElements : Symbol(IntrinsicElements, Decl(file.tsx, 1, 22))
[s: string]: any;
>s : Symbol(s, Decl(file.tsx, 3, 3))
}
}
declare var React: any;
>React : Symbol(React, Decl(file.tsx, 6, 11))
<>hi</div> // Error
<>eof // Error

View file

@ -0,0 +1,24 @@
=== tests/cases/conformance/jsx/file.tsx ===
declare module JSX {
>JSX : any
interface Element { }
>Element : Element
interface IntrinsicElements {
>IntrinsicElements : IntrinsicElements
[s: string]: any;
>s : string
}
}
declare var React: any;
>React : any
<>hi</div> // Error
><>hi</div> // Error<>eof // Error : JSX.Element
><>hi</div> : JSX.Element
<>eof // Error
><>eof // Error : JSX.Element

View file

@ -0,0 +1,23 @@
//// [file.tsx]
declare module JSX {
interface Element { }
interface IntrinsicElements {
[s: string]: any;
}
}
declare var React: any;
<></>; // no whitespace
< ></ >; // lots of whitespace
< /*starting wrap*/ ></ /*ending wrap*/>; // comments in the tags
<>hi</>; // text inside
<><span>hi</span><div>bye</div></>; // children
<><span>1</span><><span>2.1</span><span>2.2</span></><span>3</span></>; // nested fragments
//// [file.jsx]
<></>; // no whitespace
<></>; // lots of whitespace
<></>; // comments in the tags
<>hi</>; // text inside
<><span>hi</span><div>bye</div></>; // children
<><span>1</span><><span>2.1</span><span>2.2</span></><span>3</span></>; // nested fragments

View file

@ -0,0 +1,37 @@
=== tests/cases/conformance/jsx/file.tsx ===
declare module JSX {
>JSX : Symbol(JSX, Decl(file.tsx, 0, 0))
interface Element { }
>Element : Symbol(Element, Decl(file.tsx, 0, 20))
interface IntrinsicElements {
>IntrinsicElements : Symbol(IntrinsicElements, Decl(file.tsx, 1, 22))
[s: string]: any;
>s : Symbol(s, Decl(file.tsx, 3, 3))
}
}
declare var React: any;
>React : Symbol(React, Decl(file.tsx, 6, 11))
<></>; // no whitespace
< ></ >; // lots of whitespace
< /*starting wrap*/ ></ /*ending wrap*/>; // comments in the tags
<>hi</>; // text inside
<><span>hi</span><div>bye</div></>; // children
>span : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22))
>span : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22))
>div : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22))
>div : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22))
<><span>1</span><><span>2.1</span><span>2.2</span></><span>3</span></>; // nested fragments
>span : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22))
>span : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22))
>span : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22))
>span : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22))
>span : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22))
>span : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22))
>span : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22))
>span : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22))

View file

@ -0,0 +1,54 @@
=== tests/cases/conformance/jsx/file.tsx ===
declare module JSX {
>JSX : any
interface Element { }
>Element : Element
interface IntrinsicElements {
>IntrinsicElements : IntrinsicElements
[s: string]: any;
>s : string
}
}
declare var React: any;
>React : any
<></>; // no whitespace
><></> : JSX.Element
< ></ >; // lots of whitespace
>< ></ > : JSX.Element
< /*starting wrap*/ ></ /*ending wrap*/>; // comments in the tags
>< /*starting wrap*/ ></ /*ending wrap*/> : JSX.Element
<>hi</>; // text inside
><>hi</> : JSX.Element
<><span>hi</span><div>bye</div></>; // children
><><span>hi</span><div>bye</div></> : JSX.Element
><span>hi</span> : JSX.Element
>span : any
>span : any
><div>bye</div> : JSX.Element
>div : any
>div : any
<><span>1</span><><span>2.1</span><span>2.2</span></><span>3</span></>; // nested fragments
><><span>1</span><><span>2.1</span><span>2.2</span></><span>3</span></> : JSX.Element
><span>1</span> : JSX.Element
>span : any
>span : any
><><span>2.1</span><span>2.2</span></> : JSX.Element
><span>2.1</span> : JSX.Element
>span : any
>span : any
><span>2.2</span> : JSX.Element
>span : any
>span : any
><span>3</span> : JSX.Element
>span : any
>span : any

View file

@ -0,0 +1,30 @@
//// [file.tsx]
declare module JSX {
interface Element { }
interface IntrinsicElements {
[s: string]: any;
}
}
declare var React: any;
<></>; // no whitespace
< ></ >; // lots of whitespace
< /*starting wrap*/ ></ /*ending wrap*/>; // comments in the tags
<>hi</>; // text inside
<><span>hi</span><div>bye</div></>; // children
<><span>1</span><><span>2.1</span><span>2.2</span></><span>3</span></>; // nested fragments
//// [file.js]
React.createElement(React.Fragment, null); // no whitespace
React.createElement(React.Fragment, null); // lots of whitespace
React.createElement(React.Fragment, null); // comments in the tags
React.createElement(React.Fragment, null, "hi"); // text inside
React.createElement(React.Fragment, null,
React.createElement("span", null, "hi"),
React.createElement("div", null, "bye")); // children
React.createElement(React.Fragment, null,
React.createElement("span", null, "1"),
React.createElement(React.Fragment, null,
React.createElement("span", null, "2.1"),
React.createElement("span", null, "2.2")),
React.createElement("span", null, "3")); // nested fragments

View file

@ -0,0 +1,37 @@
=== tests/cases/conformance/jsx/file.tsx ===
declare module JSX {
>JSX : Symbol(JSX, Decl(file.tsx, 0, 0))
interface Element { }
>Element : Symbol(Element, Decl(file.tsx, 0, 20))
interface IntrinsicElements {
>IntrinsicElements : Symbol(IntrinsicElements, Decl(file.tsx, 1, 22))
[s: string]: any;
>s : Symbol(s, Decl(file.tsx, 3, 3))
}
}
declare var React: any;
>React : Symbol(React, Decl(file.tsx, 6, 11))
<></>; // no whitespace
< ></ >; // lots of whitespace
< /*starting wrap*/ ></ /*ending wrap*/>; // comments in the tags
<>hi</>; // text inside
<><span>hi</span><div>bye</div></>; // children
>span : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22))
>span : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22))
>div : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22))
>div : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22))
<><span>1</span><><span>2.1</span><span>2.2</span></><span>3</span></>; // nested fragments
>span : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22))
>span : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22))
>span : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22))
>span : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22))
>span : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22))
>span : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22))
>span : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22))
>span : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 1, 22))

View file

@ -0,0 +1,54 @@
=== tests/cases/conformance/jsx/file.tsx ===
declare module JSX {
>JSX : any
interface Element { }
>Element : Element
interface IntrinsicElements {
>IntrinsicElements : IntrinsicElements
[s: string]: any;
>s : string
}
}
declare var React: any;
>React : any
<></>; // no whitespace
><></> : JSX.Element
< ></ >; // lots of whitespace
>< ></ > : JSX.Element
< /*starting wrap*/ ></ /*ending wrap*/>; // comments in the tags
>< /*starting wrap*/ ></ /*ending wrap*/> : JSX.Element
<>hi</>; // text inside
><>hi</> : JSX.Element
<><span>hi</span><div>bye</div></>; // children
><><span>hi</span><div>bye</div></> : JSX.Element
><span>hi</span> : JSX.Element
>span : any
>span : any
><div>bye</div> : JSX.Element
>div : any
>div : any
<><span>1</span><><span>2.1</span><span>2.2</span></><span>3</span></>; // nested fragments
><><span>1</span><><span>2.1</span><span>2.2</span></><span>3</span></> : JSX.Element
><span>1</span> : JSX.Element
>span : any
>span : any
><><span>2.1</span><span>2.2</span></> : JSX.Element
><span>2.1</span> : JSX.Element
>span : any
>span : any
><span>2.2</span> : JSX.Element
>span : any
>span : any
><span>3</span> : JSX.Element
>span : any
>span : any

View file

@ -0,0 +1,7 @@
//@jsx: react
//@jsxfactory: h
declare var h: any;
<></>;
<><span>1</span><><span>2.1</span><span>2.2</span></></>;

View file

@ -0,0 +1,48 @@
// @filename: file.tsx
// @jsx: preserve
// @noLib: true
// @skipLibCheck: true
// @libFiles: react.d.ts,lib.d.ts
import React = require('react');
interface Prop {
a: number,
b: string,
children: JSX.Element | JSX.Element[];
}
class Button extends React.Component<any, any> {
render() {
return (<div>My Button</div>)
}
}
function AnotherButton(p: any) {
return <h1>Just Another Button</h1>;
}
function Comp(p: Prop) {
return <div>{p.b}</div>;
}
// OK
let k1 = <Comp a={10} b="hi"><></><Button /><AnotherButton /></Comp>;
let k2 = <Comp a={10} b="hi"><><Button /></><AnotherButton /></Comp>;
let k3 = <Comp a={10} b="hi"><><Button /><AnotherButton /></></Comp>;
interface SingleChildProp {
a: number,
b: string,
children: JSX.Element;
}
function SingleChildComp(p: SingleChildProp) {
return <div>{p.b}</div>;
}
// OK
let k4 = <SingleChildComp a={10} b="hi"><><Button /><AnotherButton /></></SingleChildComp>;
// Error
let k5 = <SingleChildComp a={10} b="hi"><></><Button /><AnotherButton /></SingleChildComp>;

View file

@ -0,0 +1,14 @@
//@filename: file.tsx
//@jsx: react
declare module JSX {
interface Element { }
interface IntrinsicElements {
[s: string]: any;
}
}
declare var React: any;
<>hi</div> // Error
<>eof // Error

View file

@ -0,0 +1,17 @@
//@filename: file.tsx
//@jsx: preserve
declare module JSX {
interface Element { }
interface IntrinsicElements {
[s: string]: any;
}
}
declare var React: any;
<></>; // no whitespace
< ></ >; // lots of whitespace
< /*starting wrap*/ ></ /*ending wrap*/>; // comments in the tags
<>hi</>; // text inside
<><span>hi</span><div>bye</div></>; // children
<><span>1</span><><span>2.1</span><span>2.2</span></><span>3</span></>; // nested fragments

View file

@ -0,0 +1,17 @@
//@filename: file.tsx
//@jsx: react
declare module JSX {
interface Element { }
interface IntrinsicElements {
[s: string]: any;
}
}
declare var React: any;
<></>; // no whitespace
< ></ >; // lots of whitespace
< /*starting wrap*/ ></ /*ending wrap*/>; // comments in the tags
<>hi</>; // text inside
<><span>hi</span><div>bye</div></>; // children
<><span>1</span><><span>2.1</span><span>2.2</span></><span>3</span></>; // nested fragments