From 30dd720c70f7d1af667cdaf8cef7805b8a651ad6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Tue, 19 May 2015 08:31:09 +0200 Subject: [PATCH 1/8] add support for '.tsx' files --- src/compiler/commandLineParser.ts | 15 +++++++++++++-- src/compiler/core.ts | 4 ++-- src/harness/compilerRunner.ts | 16 ++++++++-------- src/harness/runnerbase.ts | 2 +- 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 7a589fe61cb3b..355e2617a970b 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -397,10 +397,21 @@ module ts { } } else { - var sysFiles = host.readDirectory(basePath, ".ts"); + var sysFiles = host.readDirectory(basePath, ".ts").concat(host.readDirectory(basePath, ".tsx")); for (var i = 0; i < sysFiles.length; i++) { var name = sysFiles[i]; - if (!fileExtensionIs(name, ".d.ts") || !contains(sysFiles, name.substr(0, name.length - 5) + ".ts")) { + if (fileExtensionIs(name, ".d.ts")) { + let baseName = name.substr(0, name.length - ".d.ts".length); + if (!contains(sysFiles, baseName + ".tsx") && !contains(sysFiles, baseName + ".ts")) { + files.push(name); + } + } + else if (fileExtensionIs(name, ".ts")) { + if (!contains(sysFiles, name + "x")) { + files.push(name) + } + } + else { files.push(name); } } diff --git a/src/compiler/core.ts b/src/compiler/core.ts index ef7c892be9d31..bf248ba8926a8 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -653,9 +653,9 @@ module ts { /** * List of supported extensions in order of file resolution precedence. */ - export const supportedExtensions = [".ts", ".d.ts"]; + export const supportedExtensions = [".tsx", ".ts", ".d.ts"]; - const extensionsToRemove = [".d.ts", ".ts", ".js"]; + const extensionsToRemove = [".d.ts", ".ts", ".tsx", ".js"]; export function removeFileExtension(path: string): string { for (let ext of extensionsToRemove) { if (fileExtensionIs(path, ext)) { diff --git a/src/harness/compilerRunner.ts b/src/harness/compilerRunner.ts index b6997e705b9f1..fa6dcf81ec429 100644 --- a/src/harness/compilerRunner.ts +++ b/src/harness/compilerRunner.ts @@ -150,7 +150,7 @@ class CompilerBaselineRunner extends RunnerBase { // check errors it('Correct errors for ' + fileName, () => { if (this.errors) { - Harness.Baseline.runBaseline('Correct errors for ' + fileName, justName.replace(/\.ts$/, '.errors.txt'), (): string => { + Harness.Baseline.runBaseline('Correct errors for ' + fileName, justName.replace(/\.tsx?$/, '.errors.txt'), (): string => { if (result.errors.length === 0) return null; return getErrorBaseline(toBeCompiled, otherFiles, result); }); @@ -160,7 +160,7 @@ class CompilerBaselineRunner extends RunnerBase { // Source maps? it('Correct sourcemap content for ' + fileName, () => { if (options.sourceMap || options.inlineSourceMap) { - Harness.Baseline.runBaseline('Correct sourcemap content for ' + fileName, justName.replace(/\.ts$/, '.sourcemap.txt'), () => { + Harness.Baseline.runBaseline('Correct sourcemap content for ' + fileName, justName.replace(/\.tsx?$/, '.sourcemap.txt'), () => { var record = result.getSourceMapRecord(); if (options.noEmitOnError && result.errors.length !== 0 && record === undefined) { // Because of the noEmitOnError option no files are created. We need to return null because baselining isn't required. @@ -179,7 +179,7 @@ class CompilerBaselineRunner extends RunnerBase { } // check js output - Harness.Baseline.runBaseline('Correct JS output for ' + fileName, justName.replace(/\.ts/, '.js'), () => { + Harness.Baseline.runBaseline('Correct JS output for ' + fileName, justName.replace(/\.tsx?/, '.js'), () => { var tsCode = ''; var tsSources = otherFiles.concat(toBeCompiled); if (tsSources.length > 1) { @@ -239,7 +239,7 @@ class CompilerBaselineRunner extends RunnerBase { throw new Error('Number of sourcemap files should be same as js files.'); } - Harness.Baseline.runBaseline('Correct Sourcemap output for ' + fileName, justName.replace(/\.ts/, '.js.map'), () => { + Harness.Baseline.runBaseline('Correct Sourcemap output for ' + fileName, justName.replace(/\.tsx?/, '.js.map'), () => { if (options.noEmitOnError && result.errors.length !== 0 && result.sourceMaps.length === 0) { // We need to return null here or the runBaseLine will actually create a empty file. // Baselining isn't required here because there is no output. @@ -324,11 +324,11 @@ class CompilerBaselineRunner extends RunnerBase { let pullExtension = isSymbolBaseLine ? '.symbols.pull' : '.types.pull'; if (fullBaseLine !== pullBaseLine) { - Harness.Baseline.runBaseline('Correct full information for ' + fileName, justName.replace(/\.ts/, fullExtension), () => fullBaseLine); - Harness.Baseline.runBaseline('Correct pull information for ' + fileName, justName.replace(/\.ts/, pullExtension), () => pullBaseLine); + Harness.Baseline.runBaseline('Correct full information for ' + fileName, justName.replace(/\.tsx?/, fullExtension), () => fullBaseLine); + Harness.Baseline.runBaseline('Correct pull information for ' + fileName, justName.replace(/\.tsx?/, pullExtension), () => pullBaseLine); } else { - Harness.Baseline.runBaseline('Correct information for ' + fileName, justName.replace(/\.ts/, fullExtension), () => fullBaseLine); + Harness.Baseline.runBaseline('Correct information for ' + fileName, justName.replace(/\.tsx?/, fullExtension), () => fullBaseLine); } } @@ -395,7 +395,7 @@ class CompilerBaselineRunner extends RunnerBase { // this will set up a series of describe/it blocks to run between the setup and cleanup phases if (this.tests.length === 0) { - var testFiles = this.enumerateFiles(this.basePath, /\.ts$/, { recursive: true }); + var testFiles = this.enumerateFiles(this.basePath, /\.tsx?$/, { recursive: true }); testFiles.forEach(fn => { fn = fn.replace(/\\/g, "/"); this.checkTestCodeOutput(fn); diff --git a/src/harness/runnerbase.ts b/src/harness/runnerbase.ts index 49ca796448a47..663a2522ed3d6 100644 --- a/src/harness/runnerbase.ts +++ b/src/harness/runnerbase.ts @@ -27,7 +27,7 @@ class RunnerBase { var fixedPath = path; // full paths either start with a drive letter or / for *nix, shouldn't have \ in the path at this point - var fullPath = /(\w+:|\/)?([\w+\-\.]|\/)*\.ts/g; + var fullPath = /(\w+:|\/)?([\w+\-\.]|\/)*\.tsx?/g; var fullPathList = fixedPath.match(fullPath); if (fullPathList) { fullPathList.forEach((match: string) => fixedPath = fixedPath.replace(match, Harness.Path.getFileName(match))); From 45b138cec7dca5b15075bd10d490346341ea8217 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Tue, 19 May 2015 08:37:47 +0200 Subject: [PATCH 2/8] types for JSX elements --- src/compiler/types.ts | 44 ++++++++++++++++++++++++++++++++++++++++ src/services/services.ts | 1 + 2 files changed, 45 insertions(+) diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 86e680ca8b047..e2f4c53529520 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -40,6 +40,7 @@ module ts { SemicolonToken, CommaToken, LessThanToken, + LessThanSlashToken, GreaterThanToken, LessThanEqualsToken, GreaterThanEqualsToken, @@ -252,6 +253,15 @@ module ts { ExportSpecifier, MissingDeclaration, + //JSX + JSXElement, + JSXOpeningElement, + JSXText, + JSXClosingElement, + JSXAttribute, + JSXSpreadAttribute, + JSXExpression, + // Module references ExternalModuleReference, @@ -895,6 +905,39 @@ module ts { token: SyntaxKind; types?: NodeArray; } + + export interface JSXElement extends PrimaryExpression { + openingElement: JSXOpeningElement; + children?: NodeArray; + closingElement?: JSXClosingElement; + } + + export interface JSXOpeningElement extends Node { + tagName: EntityName; + attributes: NodeArray; + isSelfClosing: boolean; + } + + export interface JSXAttribute extends Node { + name: Identifier; + initializer?: Expression; + } + + export interface JSXSpreadAttribute extends Node { + expression: Expression; + } + + export interface JSXClosingElement extends Node { + tagName: EntityName; + } + + export interface JSXExpression extends Expression { + expression?: Expression; + } + + export interface JSXText extends Node { + _jsxTextBrand: any; + } export interface TypeAliasDeclaration extends Declaration, ModuleElement { name: Identifier; @@ -1003,6 +1046,7 @@ module ts { amdDependencies: {path: string; name: string}[]; amdModuleName: string; referencedFiles: FileReference[]; + isTSXFile: boolean; hasNoDefaultLib: boolean; diff --git a/src/services/services.ts b/src/services/services.ts index a6a26f0b60b7a..ca725d536004e 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -737,6 +737,7 @@ module ts { public amdDependencies: { name: string; path: string }[]; public amdModuleName: string; public referencedFiles: FileReference[]; + public isTSXFile: boolean; public syntacticDiagnostics: Diagnostic[]; public referenceDiagnostics: Diagnostic[]; From 78dd3e081f1ef8d4746cf81ba9eb66decab65f9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Tue, 19 May 2015 08:38:01 +0200 Subject: [PATCH 3/8] utilities for JSX elements --- src/compiler/utilities.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 356337e1315cb..63153ec65c0c9 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -733,6 +733,8 @@ module ts { case SyntaxKind.TemplateExpression: case SyntaxKind.NoSubstitutionTemplateLiteral: case SyntaxKind.OmittedExpression: + case SyntaxKind.JSXElement: + case SyntaxKind.JSXExpression: return true; case SyntaxKind.QualifiedName: while (node.parent.kind === SyntaxKind.QualifiedName) { @@ -1652,6 +1654,7 @@ module ts { case SyntaxKind.ElementAccessExpression: case SyntaxKind.NewExpression: case SyntaxKind.CallExpression: + case SyntaxKind.JSXElement: case SyntaxKind.TaggedTemplateExpression: case SyntaxKind.ArrayLiteralExpression: case SyntaxKind.ParenthesizedExpression: From 06fd51d05b3c9b8ec27708168565be7a58666406 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Tue, 19 May 2015 08:59:49 +0200 Subject: [PATCH 4/8] diagnostics for jsx elements --- .../diagnosticInformationMap.generated.ts | 6 +++++ src/compiler/diagnosticMessages.json | 24 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 32dc590eeecff..77a71a44b55ab 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -545,5 +545,11 @@ module ts { Only_identifiers_Slashqualified_names_with_optional_type_arguments_are_currently_supported_in_a_class_extends_clauses: { code: 9002, category: DiagnosticCategory.Error, key: "Only identifiers/qualified-names with optional type arguments are currently supported in a class 'extends' clauses." }, class_expressions_are_not_currently_supported: { code: 9003, category: DiagnosticCategory.Error, key: "'class' expressions are not currently supported." }, class_declarations_are_only_supported_directly_inside_a_module_or_as_a_top_level_declaration: { code: 9004, category: DiagnosticCategory.Error, key: "'class' declarations are only supported directly inside a module or as a top level declaration." }, + JSX_attributes_must_only_be_assigned_a_non_empty_expression: { code: 17000, category: DiagnosticCategory.Error, key: "JSX attributes must only be assigned a non-empty 'expression'." }, + JSX_elements_cannot_have_multiple_attributes_with_the_same_name: { code: 17001, category: DiagnosticCategory.Error, key: "JSX elements cannot have multiple attributes with the same name." }, + Expected_corresponding_JSX_closing_tag_for_0: { code: 17002, category: DiagnosticCategory.Error, key: "Expected corresponding JSX closing tag for '{0}'." }, + JSX_attribute_expected: { code: 17003, category: DiagnosticCategory.Error, key: "JSX attribute expected." }, + JSX_factory_cannot_have_multiple_assignments: { code: 17004, category: DiagnosticCategory.Error, key: "JSX factory cannot have multiple assignments." }, + JSX_elements_are_not_currently_supported: { code: 17005, category: DiagnosticCategory.Error, key: "JSX elements are not currently supported." }, }; } \ No newline at end of file diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index a3dfd62d34e75..1923530a728ce 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2172,5 +2172,29 @@ "'class' declarations are only supported directly inside a module or as a top level declaration.": { "category": "Error", "code": 9004 + }, + "JSX attributes must only be assigned a non-empty 'expression'.": { + "category": "Error", + "code": 17000 + }, + "JSX elements cannot have multiple attributes with the same name.": { + "category": "Error", + "code": 17001 + }, + "Expected corresponding JSX closing tag for '{0}'.": { + "category": "Error", + "code": 17002 + }, + "JSX attribute expected.": { + "category": "Error", + "code": 17003 + }, + "JSX factory cannot have multiple assignments.": { + "category": "Error", + "code": 17004 + }, + "JSX elements are not currently supported.": { + "category": "Error", + "code" : 17005 } } From 98fdc8fc8423730a7d0abdd8d2500058492cd01e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Tue, 19 May 2015 09:00:00 +0200 Subject: [PATCH 5/8] parsing for jsx elements --- src/compiler/parser.ts | 245 +++++++++++++++++++++++++++++++++++++++- src/compiler/scanner.ts | 67 +++++++++++ 2 files changed, 311 insertions(+), 1 deletion(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index af9b486a1da4f..a0da2d4eca443 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -315,6 +315,22 @@ module ts { return visitNode(cbNode, (node).expression); case SyntaxKind.MissingDeclaration: return visitNodes(cbNodes, node.decorators); + case SyntaxKind.JSXElement: + return visitNode(cbNode, (node).openingElement) || + visitNodes(cbNodes, (node).children) || + visitNode(cbNode, (node).closingElement); + case SyntaxKind.JSXOpeningElement: + return visitNode(cbNode, (node).tagName) || + visitNodes(cbNodes, (node).attributes); + case SyntaxKind.JSXAttribute: + return visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).initializer); + case SyntaxKind.JSXSpreadAttribute: + return visitNode(cbNode, (node).expression); + case SyntaxKind.JSXExpression: + return visitNode(cbNode, (node).expression); + case SyntaxKind.JSXClosingElement: + return visitNode(cbNode, (node).tagName); } } @@ -436,6 +452,8 @@ module ts { // attached to the EOF token. let parseErrorBeforeNextFinishedNode: boolean = false; + let closingTagsMap: Map; + export function parseSourceFile(fileName: string, _sourceText: string, languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor, setParentNodes?: boolean): SourceFile { sourceText = _sourceText; syntaxCursor = _syntaxCursor; @@ -447,6 +465,7 @@ module ts { contextFlags = 0; parseErrorBeforeNextFinishedNode = false; + closingTagsMap = null; createSourceFile(fileName, languageVersion); @@ -526,6 +545,7 @@ module ts { sourceFile.languageVersion = languageVersion; sourceFile.fileName = normalizePath(fileName); sourceFile.flags = fileExtensionIs(sourceFile.fileName, ".d.ts") ? NodeFlags.DeclarationFile : 0; + sourceFile.isTSXFile = fileExtensionIs(sourceFile.fileName, ".tsx"); } function setContextFlag(val: Boolean, flag: ParserContextFlags) { @@ -702,6 +722,14 @@ module ts { return token = scanner.reScanTemplateToken(); } + function reScanJSXIdentifier(): SyntaxKind { + return token = scanner.reScanJSXIdentifier(); + } + + function reScanLessThanToken(): SyntaxKind { + return token = scanner.reScanLessThanToken(); + } + function speculationHelper(callback: () => T, isLookAhead: boolean): T { // Keep track of the state we'll need to rollback to if lookahead fails (or if the // caller asked us to always reset our state). @@ -1057,6 +1085,8 @@ module ts { return isHeritageClause(); case ParsingContext.ImportOrExportSpecifiers: return isIdentifierOrKeyword(); + case ParsingContext.JSXAttributes: + return isIdentifier() || token === SyntaxKind.OpenBraceToken; } Debug.fail("Non-exhaustive case in 'isListElement'."); @@ -1142,6 +1172,8 @@ module ts { return token === SyntaxKind.GreaterThanToken || token === SyntaxKind.OpenParenToken; case ParsingContext.HeritageClauses: return token === SyntaxKind.OpenBraceToken || token === SyntaxKind.CloseBraceToken; + case ParsingContext.JSXAttributes: + return token === SyntaxKind.GreaterThanToken || token === SyntaxKind.SlashToken || token === SyntaxKind.CloseBraceToken; } } @@ -1547,6 +1579,7 @@ module ts { case ParsingContext.TupleElementTypes: return Diagnostics.Type_expected; case ParsingContext.HeritageClauses: return Diagnostics.Unexpected_token_expected; case ParsingContext.ImportOrExportSpecifiers: return Diagnostics.Identifier_expected; + case ParsingContext.JSXAttributes: return Diagnostics.Identifier_expected; } }; @@ -2927,7 +2960,7 @@ module ts { case SyntaxKind.VoidKeyword: return parseVoidExpression(); case SyntaxKind.LessThanToken: - return parseTypeAssertion(); + return (sourceFile.isTSXFile && tryParse(() => parseJSXElement(true))) || parseTypeAssertion(); default: return parsePostfixExpressionOrHigher(); } @@ -3054,6 +3087,215 @@ module ts { node.name = parseRightSideOfDot(/*allowIdentifierNames:*/ true); return finishNode(node); } + + // Return a string representation of an EntityName + function entityNameToString(entityName: EntityName): string { + if (entityName.kind === SyntaxKind.Identifier) { + return (entityName).text; + } else { + let qualifiedName = entityName; + return entityNameToString(qualifiedName.left) + '.' + entityNameToString(qualifiedName.right); + } + return ""; + } + + function hasClosingTagAfterPos(tagName: string, currentPos: number): boolean { + if (!closingTagsMap) { + closingTagsMap = retrieveClosingTagsMap(sourceText, sourceFile.languageVersion); + } + return hasProperty(closingTagsMap, tagName) && forEach(closingTagsMap[tagName], p => p >= currentPos); + } + + function parseJSXElement(speculative = false): JSXElement { + let node = createNode(SyntaxKind.JSXElement); + + node.openingElement = parseJSXOpeningElement(); + + let tagName = entityNameToString(node.openingElement.tagName); + + if (node.openingElement.attributes.length && tagName) { + // if there is tagName and attribute it's sure that we are in a JSXElement and not a type assertion + speculative = false; + } + + node.children = >[]; + node.children.pos = getNodePos(); + + if (node.openingElement.isSelfClosing) { + node.children.end = getNodeEnd(); + // if it's a self closing tag it's a JSXElement and not a type assertion + speculative = false; + } + else { + if (speculative && !hasClosingTagAfterPos(tagName, scanner.getStartPos())) { + // we are in speculative parsing and we were not able to find a corresponding closing tag + // farther in the source text, we try to determine if the following tokens look like normal + // part of jsx children to decide if we continue parsing the JSXElement children + let shouldContinueJSXParsing = lookAhead(() => { + const t = token; + const next = nextToken(); + return t === SyntaxKind.LessThanToken ||// <... + (t >= SyntaxKind.Identifier && next === SyntaxKind.OpenBraceToken) || // ' bar {... + (t >= SyntaxKind.Identifier && next >= SyntaxKind.Identifier) // ' foo bar ... + }); + if (!shouldContinueJSXParsing) { + return null; + } + } + //we can't use parseList we need to intercept '}‘ token in speculative mode + let savedStrictModeContext = inStrictModeContext(); + + while (true) { + if (token === SyntaxKind.OpenBraceToken) { + node.children.push(parseJSXExpression()); + } + else if (token === SyntaxKind.LessThanToken) { + if (reScanLessThanToken() === SyntaxKind.LessThanSlashToken) { + break; + } + node.children.push(parseJSXElement()); + } + else if (token === SyntaxKind.CloseBraceToken || token === SyntaxKind.EndOfFileToken) { + if (speculative) { + // that means that we are generaly in case like + //
{
{}}
to desambiguate those cases + // we forbid the } token in jsx text (use entity); + return null; + } + parseErrorAtCurrentToken(Diagnostics.Unexpected_token); + break; + } + else { + node.children.push(parseJSXText()) + } + } + + setStrictModeContext(savedStrictModeContext); + node.children.end = getNodeEnd(); + + if (token === SyntaxKind.LessThanSlashToken) { + + let start = scanner.getStartPos(); + node.closingElement = parseJSXClosingElement(); + if (!node.closingElement.tagName || tagName !== entityNameToString(node.closingElement.tagName)) { + var length = scanner.getTokenPos() - start; + parseErrorAtPosition(start, length, Diagnostics.Expected_corresponding_JSX_closing_tag_for_0, tagName); + } + speculative = false; + } + else { + node.closingElement = createMissingNode(SyntaxKind.JSXClosingElement, /*reportAtCurrentPosition:*/ true, + Diagnostics.Expected_corresponding_JSX_closing_tag_for_0, tagName); + node.children.end = getNodeEnd(); + } + } + + if (speculative) { + return null; + } + + return finishNode(node); + } + + function parseJSXText(): JSXText { + let node = createNode(SyntaxKind.JSXText); + while (token !== SyntaxKind.OpenBraceToken && + token !== SyntaxKind.CloseBraceToken && + token !== SyntaxKind.LessThanToken && + token !== SyntaxKind.EndOfFileToken) { + nextToken(); + } + return finishNode(node); + } + + function parseJSXOpeningElement(): JSXOpeningElement { + let node = createNode(SyntaxKind.JSXOpeningElement); + + parseExpected(SyntaxKind.LessThanToken); + node.tagName = parseJSXElementName(); + node.attributes = parseList(ParsingContext.JSXAttributes, /*checkForStrictMode*/ false, parseJSXAttribute); + if (token === SyntaxKind.SlashToken) { + node.isSelfClosing = true; + nextToken(); + } + parseExpected(SyntaxKind.GreaterThanToken); + return finishNode(node); + } + + function parseJSXElementName(): EntityName { + reScanJSXIdentifier(); + let elementName: EntityName = parseIdentifier(); + while (parseOptional(SyntaxKind.DotToken)) { + reScanJSXIdentifier(); + let node = createNode(SyntaxKind.QualifiedName, elementName.pos); + node.left = elementName; + node.right = parseIdentifierName(); + elementName = finishNode(node); + } + return elementName; + } + + function parseJSXExpression(): JSXExpression { + let node = createNode(SyntaxKind.JSXExpression) + let isExpressionEmpty = lookAhead(() => { + do { + nextToken(); + if (token === SyntaxKind.CloseBraceToken) { + return true; + } + else if (!isTrivia(token)) { + return false; + } + } while (token != SyntaxKind.EndOfFileToken); + return true; + }); + parseExpected(SyntaxKind.OpenBraceToken); + if (!isExpressionEmpty) { + node.expression = parseExpression(); + } + parseExpected(SyntaxKind.CloseBraceToken); + return finishNode(node); + } + + function parseJSXAttribute(): JSXAttribute | JSXSpreadAttribute { + if (token === SyntaxKind.OpenBraceToken) { + return parseJSXSPreadAttribute(); + } + reScanJSXIdentifier(); + let node = createNode(SyntaxKind.JSXAttribute); + node.name = parseIdentifierName(); + if (parseOptional(SyntaxKind.EqualsToken)) { + switch (token) { + case SyntaxKind.LessThanToken: + node.initializer = parseJSXElement(); + break; + case SyntaxKind.StringLiteral: + node.initializer = parseLiteralNode(); + break; + default: + node.initializer = parseJSXExpression(); + break; + } + } + return finishNode(node); + } + + function parseJSXSPreadAttribute(): JSXSpreadAttribute { + let node = createNode(SyntaxKind.JSXSpreadAttribute); + parseExpected(SyntaxKind.OpenBraceToken); + parseExpected(SyntaxKind.DotDotDotToken); + node.expression = parseExpression(); + parseExpected(SyntaxKind.CloseBraceToken); + return finishNode(node); + } + + function parseJSXClosingElement(): JSXClosingElement { + let node = createNode(SyntaxKind.JSXClosingElement); + parseExpected(SyntaxKind.LessThanSlashToken); + node.tagName = parseJSXElementName(); + parseExpected(SyntaxKind.GreaterThanToken); + return finishNode(node); + } function parseTypeAssertion(): TypeAssertion { let node = createNode(SyntaxKind.TypeAssertionExpression); @@ -4844,6 +5086,7 @@ module ts { ArrayBindingElements, // Binding elements in array binding list ArgumentExpressions, // Expressions in argument list ObjectLiteralMembers, // Members in object literal + JSXAttributes, // Attributes in jsx element ArrayLiteralMembers, // Members in array literal Parameters, // Parameters in parameter list TypeParameters, // Type parameters in type parameter list diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 1fc8bff92e677..770c7ed3b7b39 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -21,6 +21,8 @@ module ts { reScanGreaterToken(): SyntaxKind; reScanSlashToken(): SyntaxKind; reScanTemplateToken(): SyntaxKind; + reScanJSXIdentifier(): SyntaxKind; + reScanLessThanToken(): SyntaxKind; scan(): SyntaxKind; // Sets the text for the scanner to scan. An optional subrange starting point and length // can be provided to have the scanner only scan a portion of the text. @@ -129,6 +131,7 @@ module ts { "++": SyntaxKind.PlusPlusToken, "--": SyntaxKind.MinusMinusToken, "<<": SyntaxKind.LessThanLessThanToken, + ">": SyntaxKind.GreaterThanGreaterThanToken, ">>>": SyntaxKind.GreaterThanGreaterThanGreaterThanToken, "&": SyntaxKind.AmpersandToken, @@ -597,6 +600,41 @@ module ts { ch >= CharacterCodes._0 && ch <= CharacterCodes._9 || ch === CharacterCodes.$ || ch === CharacterCodes._ || ch > CharacterCodes.maxAsciiCharacter && isUnicodeIdentifierPart(ch, languageVersion); } + + /* @internal */ + export function retrieveClosingTagsMap(text: string, languageVersion: ScriptTarget): Map { + let pos = 0; + let end = text.length; + const closingTags: Map = {}; + while (pos < end) { + if (text.charCodeAt(pos) === CharacterCodes.lessThan && text.charCodeAt(pos + 1) === CharacterCodes.slash) { + let p = pos + 2; + let ch: number; + while (p < end) { + ch = text.charCodeAt(p); + if (!isIdentifierPart(ch, languageVersion) && + ch !== CharacterCodes.minus && + ch !== CharacterCodes.dot && + ch !== CharacterCodes.backslash && + !isWhiteSpace(ch) && + !isLineBreak(ch)) { + break; + } + p++; + } + if (ch === CharacterCodes.greaterThan) { + let tagName = text.substring(pos + 2, p).replace(/\s/g, ''); + if (!hasProperty(closingTags, tagName)) { + closingTags[tagName] = []; + } + closingTags[tagName].push(pos); + pos = p; + } + } + pos++; + } + return closingTags; + } /** Creates a scanner over a (possibly unspecified) range of a piece of text. */ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean, text?: string, onError?: ErrorCallback, start?: number, length?: number): Scanner { @@ -627,6 +665,8 @@ module ts { reScanGreaterToken, reScanSlashToken, reScanTemplateToken, + reScanJSXIdentifier, + reScanLessThanToken, scan, setText, setScriptTarget, @@ -1442,6 +1482,33 @@ module ts { pos = tokenPos; return token = scanTemplateAndSetTokenValue(); } + + function reScanJSXIdentifier(): SyntaxKind { + if (token === SyntaxKind.Identifier) { + while (pos < end) { + let ch = text.charCodeAt(pos); + if (ch === CharacterCodes.minus || isIdentifierPart(ch)) { + tokenValue += String.fromCharCode(ch); + pos++; + } + else if (ch === CharacterCodes.backslash) { + tokenValue += scanIdentifierParts(); + } + else { + break; + } + } + } + return token; + } + + function reScanLessThanToken(): SyntaxKind { + Debug.assert(token === SyntaxKind.LessThanToken, "'reScanLessThanToken' should only be called on a '<'"); + if (text.charCodeAt(pos) === CharacterCodes.slash) { + return pos++, token = SyntaxKind.LessThanSlashToken; + } + return token; + } function speculationHelper(callback: () => T, isLookahead: boolean): T { let savePos = pos; From 1a24143223c26e6e171f4bfe9a28da6dfc187d11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Tue, 19 May 2015 09:00:55 +0200 Subject: [PATCH 6/8] grammar check for JSXElements --- src/compiler/checker.ts | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5d26a30c3b7dd..70300faa1564d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6266,6 +6266,11 @@ module ts { } } + function checkJSXElement(node: JSXElement) { + checkGrammarJSXElement(node); + grammarErrorOnNode(node, Diagnostics.JSX_elements_are_not_currently_supported); + } + // If a symbol is a synthesized symbol with no value declaration, we assume it is a property. Example of this are the synthesized // '.prototype' property as well as synthesized tuple index properties. function getDeclarationKindFromSymbol(s: Symbol) { @@ -8164,6 +8169,9 @@ module ts { case SyntaxKind.YieldExpression: checkYieldExpression(node); return unknownType; + case SyntaxKind.JSXElement: + checkJSXElement(node); + return unknownType; } return unknownType; } @@ -12699,6 +12707,29 @@ module ts { } } + function checkGrammarJSXElement(node: JSXElement) { + const seen: Map = {}; + for (let attr of node.openingElement.attributes) { + if (attr.kind === SyntaxKind.JSXSpreadAttribute) { + continue; + } + + let jsxAttr = (attr); + let name = jsxAttr.name; + if (!hasProperty(seen, name.text)) { + seen[name.text] = true; + } + else { + return grammarErrorOnNode(name, Diagnostics.JSX_elements_cannot_have_multiple_attributes_with_the_same_name); + } + + let initializer = jsxAttr.initializer; + if (initializer && initializer.kind === SyntaxKind.JSXExpression && !(initializer).expression) { + return grammarErrorOnNode(jsxAttr.initializer, Diagnostics.JSX_attributes_must_only_be_assigned_a_non_empty_expression); + } + } + } + function checkGrammarForInOrForOfStatement(forInOrOfStatement: ForInStatement | ForOfStatement): boolean { if (checkGrammarStatementInAmbientContext(forInOrOfStatement)) { return true; From 47f10b36a02462f4482a774d755ad79b7a51ac12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Tue, 19 May 2015 09:49:07 +0200 Subject: [PATCH 7/8] test cases for jsx elements --- tests/cases/compiler/jsxReactApp.tsx | 195 ++++++++++++++++++ .../conformance/jsx/jsxAndTypeAssertion.tsx | 14 ++ .../jsx/jsxClosingTagMapsRelaxingRules.tsx | 7 + .../conformance/jsx/jsxEsprimaFbTestSuite.tsx | 46 +++++ .../jsx/jsxInvalidEsprimaTestSuite.tsx | 34 +++ .../conformance/jsx/jsxReactTestSuite.tsx | 102 +++++++++ 6 files changed, 398 insertions(+) create mode 100644 tests/cases/compiler/jsxReactApp.tsx create mode 100755 tests/cases/conformance/jsx/jsxAndTypeAssertion.tsx create mode 100644 tests/cases/conformance/jsx/jsxClosingTagMapsRelaxingRules.tsx create mode 100755 tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx create mode 100755 tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx create mode 100755 tests/cases/conformance/jsx/jsxReactTestSuite.tsx diff --git a/tests/cases/compiler/jsxReactApp.tsx b/tests/cases/compiler/jsxReactApp.tsx new file mode 100644 index 0000000000000..99487b4b59963 --- /dev/null +++ b/tests/cases/compiler/jsxReactApp.tsx @@ -0,0 +1,195 @@ +declare module React { + + interface ComponentClass

{ + new(props: any): Component; + prototype: { props: P }; + } + + interface ReactCompositeElement

{ + type: ComponentClass

; + props?: P; + key?: number | string; + ref?: string; + } + + interface ReactHtmlElement { + type: string; + props?: ReactAttributes; + key?: number | string; + ref?: string; + } + + type ReactElement = ReactCompositeElement | ReactHtmlElement; + + interface ReactElementArray extends Array { + + } + + class Component

{ + constructor(props: P, childen?: any[]); + + props: P; + state: S; + + setState(state: S, callback?: () => void): void + render(): ReactElement; + } + + interface ReactAttributes { + children?: ReactElementArray; + key?: number | string; + ref?: string; + + // Event Attributes + + dangerouslySetInnerHTML?: { + __html: string; + }; + } + + interface HTMLAttributes extends ReactAttributes { + accept?: string; + acceptCharset?: string; + accessKey?: string; + action?: string; + allowFullScreen?: boolean; + allowTransparency?: boolean; + alt?: string; + async?: boolean; + autoComplete?: boolean; + autoFocus?: boolean; + autoPlay?: boolean; + cellPadding?: number | string; + cellSpacing?: number | string; + charSet?: string; + checked?: boolean; + classID?: string; + className?: string; + cols?: number; + colSpan?: number; + content?: string; + contentEditable?: boolean; + contextMenu?: string; + controls?: any; + coords?: string; + crossOrigin?: string; + data?: string; + dateTime?: string; + defer?: boolean; + dir?: string; + disabled?: boolean; + download?: any; + draggable?: boolean; + encType?: string; + form?: string; + formNoValidate?: boolean; + frameBorder?: number | string; + height?: number | string; + hidden?: boolean; + href?: string; + hrefLang?: string; + htmlFor?: string; + httpEquiv?: string; + icon?: string; + id?: string; + label?: string; + lang?: string; + list?: string; + loop?: boolean; + manifest?: string; + max?: number | string; + maxLength?: number; + media?: string; + mediaGroup?: string; + method?: string; + min?: number | string; + multiple?: boolean; + muted?: boolean; + name?: string; + noValidate?: boolean; + open?: boolean; + pattern?: string; + placeholder?: string; + poster?: string; + preload?: string; + radioGroup?: string; + readOnly?: boolean; + rel?: string; + required?: boolean; + role?: string; + rows?: number; + rowSpan?: number; + sandbox?: string; + scope?: string; + scrollLeft?: number; + scrolling?: string; + scrollTop?: number; + seamless?: boolean; + selected?: boolean; + shape?: string; + size?: number; + sizes?: string; + span?: number; + spellCheck?: boolean; + src?: string; + srcDoc?: string; + srcSet?: string; + start?: number; + step?: number | string; + tabIndex?: number; + target?: string; + title?: string; + type?: string; + useMap?: string; + value?: string; + width?: number | string; + wmode?: string; + + // Non-standard Attributes + autoCapitalize?: boolean; + autoCorrect?: boolean; + property?: string; + itemProp?: string; + itemScope?: boolean; + itemType?: string; + } + + function createElement(type: string, props?: HTMLAttributes, ...rest: any[]): ReactHtmlElement; + function createElement

(type: ComponentClass

, props?: P, ...rest: any[]): ReactCompositeElement

; +} + +class TodoList extends React.Component<{ items: string[] },{}> { + render(): React.ReactElement { + return

    {this.props.items.map(itemText =>
  • {itemText}
  • )}
; + } +} + +class TodoApp extends React.Component<{},{items?: string[]; text?: string}> { + state = {items: [], text: ''}; + + onChange = (e: any) => { + this.setState({ + text: e.target.value + }); + } + + handleSubmit = (e: any) => { + e.preventDefault(); + var nextItems = this.state.items.concat([this.state.text]); + var nextText = ''; + this.setState({items: nextItems, text: nextText}); + } + + render(): React.ReactElement { + return ( +
+

TODO

+ +
+ + +
+
+ ); + } +} diff --git a/tests/cases/conformance/jsx/jsxAndTypeAssertion.tsx b/tests/cases/conformance/jsx/jsxAndTypeAssertion.tsx new file mode 100755 index 0000000000000..3977380f85c42 --- /dev/null +++ b/tests/cases/conformance/jsx/jsxAndTypeAssertion.tsx @@ -0,0 +1,14 @@ + + { test: }; + +; + +hello {{}} ; + +{}}>hello; + +{}}>hello{{}}; + +{{/foo/.test(x) ? : }} + + diff --git a/tests/cases/conformance/jsx/jsxClosingTagMapsRelaxingRules.tsx b/tests/cases/conformance/jsx/jsxClosingTagMapsRelaxingRules.tsx new file mode 100644 index 0000000000000..5a449d3d69d90 --- /dev/null +++ b/tests/cases/conformance/jsx/jsxClosingTagMapsRelaxingRules.tsx @@ -0,0 +1,7 @@ +; + foo {}; + foo bar; + Hello \ No newline at end of file diff --git a/tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx b/tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx new file mode 100755 index 0000000000000..e60b6fd876488 --- /dev/null +++ b/tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx @@ -0,0 +1,46 @@ + +; + +//; Namespace unsuported + +// {value} ; Namespace unsuported + +; + +; +; + +<日本語>; + + +bar +baz +; + + : } />; + +{}; + +{/* this is a comment */}; + +
@test content
; + +

7x invalid-js-identifier
; + + right=monkeys /> gorillas />; + +; + +; + +(
) < x; + +
; + +
; + +
; + + ; diff --git a/tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx b/tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx new file mode 100755 index 0000000000000..92a800f22f85a --- /dev/null +++ b/tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx @@ -0,0 +1,34 @@ + +; +; +<:a />; +; +; +; +; +; +
; +
; + +
stuff
; +
stuff
; + +
>; + >; +; +; +}; +; \ No newline at end of file diff --git a/tests/cases/conformance/jsx/jsxReactTestSuite.tsx b/tests/cases/conformance/jsx/jsxReactTestSuite.tsx new file mode 100755 index 0000000000000..831ae0cf5be04 --- /dev/null +++ b/tests/cases/conformance/jsx/jsxReactTestSuite.tsx @@ -0,0 +1,102 @@ +
text
; + +
+ {this.props.children} +
; + +
+

+ {foo}
{bar}
+
+
; + + + + {this.props.children} +; + + + +; + +var x = +
+
; + +( +
+ {/* A comment at the beginning */} + {/* A second comment at the beginning */} + + {/* A nested comment */} + + {/* A sandwiched comment */} +
+ {/* A comment at the end */} + {/* A second comment at the end */} +
+); + +( +
+ +
+); + +
 
; + +
 
; + +testing; + +; + +; + +; + +; + +; + +; + +; + +; + +; + +; + +; + +; + + +; + +Text; + + From 8d8896512ef0a9116079ef34a5e4adf32fed0c08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20de=20Campredon?= Date: Tue, 19 May 2015 09:49:26 +0200 Subject: [PATCH 8/8] accept baseline --- tests/baselines/reference/APISample_linter.js | 22 +- .../reference/jsxAndTypeAssertion.errors.txt | 36 +++ .../reference/jsxAndTypeAssertion.js | 24 ++ .../jsxClosingTagMapsRelaxingRules.errors.txt | 19 ++ .../jsxClosingTagMapsRelaxingRules.js | 14 ++ .../jsxEsprimaFbTestSuite.errors.txt | 115 +++++++++ .../reference/jsxEsprimaFbTestSuite.js | 71 ++++++ .../jsxInvalidEsprimaTestSuite.errors.txt | 205 +++++++++++++++ .../reference/jsxInvalidEsprimaTestSuite.js | 59 +++++ .../reference/jsxReactApp.errors.txt | 212 ++++++++++++++++ tests/baselines/reference/jsxReactApp.js | 238 ++++++++++++++++++ .../reference/jsxReactTestSuite.errors.txt | 225 +++++++++++++++++ .../baselines/reference/jsxReactTestSuite.js | 131 ++++++++++ .../amd/invalidRootFile.errors.txt | 4 +- .../node/invalidRootFile.errors.txt | 4 +- 15 files changed, 1364 insertions(+), 15 deletions(-) create mode 100644 tests/baselines/reference/jsxAndTypeAssertion.errors.txt create mode 100644 tests/baselines/reference/jsxAndTypeAssertion.js create mode 100644 tests/baselines/reference/jsxClosingTagMapsRelaxingRules.errors.txt create mode 100644 tests/baselines/reference/jsxClosingTagMapsRelaxingRules.js create mode 100644 tests/baselines/reference/jsxEsprimaFbTestSuite.errors.txt create mode 100644 tests/baselines/reference/jsxEsprimaFbTestSuite.js create mode 100644 tests/baselines/reference/jsxInvalidEsprimaTestSuite.errors.txt create mode 100644 tests/baselines/reference/jsxInvalidEsprimaTestSuite.js create mode 100644 tests/baselines/reference/jsxReactApp.errors.txt create mode 100644 tests/baselines/reference/jsxReactApp.js create mode 100644 tests/baselines/reference/jsxReactTestSuite.errors.txt create mode 100644 tests/baselines/reference/jsxReactTestSuite.js diff --git a/tests/baselines/reference/APISample_linter.js b/tests/baselines/reference/APISample_linter.js index cd2df23ffbf4f..48a0d947724d4 100644 --- a/tests/baselines/reference/APISample_linter.js +++ b/tests/baselines/reference/APISample_linter.js @@ -75,28 +75,28 @@ function delint(sourceFile) { delintNode(sourceFile); function delintNode(node) { switch (node.kind) { - case 187 /* ForStatement */: - case 188 /* ForInStatement */: - case 186 /* WhileStatement */: - case 185 /* DoStatement */: - if (node.statement.kind !== 180 /* Block */) { + case 188 /* ForStatement */: + case 189 /* ForInStatement */: + case 187 /* WhileStatement */: + case 186 /* DoStatement */: + if (node.statement.kind !== 181 /* Block */) { report(node, "A looping statement's contents should be wrapped in a block body."); } break; - case 184 /* IfStatement */: + case 185 /* IfStatement */: var ifStatement = node; - if (ifStatement.thenStatement.kind !== 180 /* Block */) { + if (ifStatement.thenStatement.kind !== 181 /* Block */) { report(ifStatement.thenStatement, "An if statement's contents should be wrapped in a block body."); } if (ifStatement.elseStatement && - ifStatement.elseStatement.kind !== 180 /* Block */ && - ifStatement.elseStatement.kind !== 184 /* IfStatement */) { + ifStatement.elseStatement.kind !== 181 /* Block */ && + ifStatement.elseStatement.kind !== 185 /* IfStatement */) { report(ifStatement.elseStatement, "An else statement's contents should be wrapped in a block body."); } break; - case 170 /* BinaryExpression */: + case 171 /* BinaryExpression */: var op = node.operatorToken.kind; - if (op === 28 /* EqualsEqualsToken */ || op == 29 /* ExclamationEqualsToken */) { + if (op === 29 /* EqualsEqualsToken */ || op == 30 /* ExclamationEqualsToken */) { report(node, "Use '===' and '!=='."); } break; diff --git a/tests/baselines/reference/jsxAndTypeAssertion.errors.txt b/tests/baselines/reference/jsxAndTypeAssertion.errors.txt new file mode 100644 index 0000000000000..353e7b3e0755a --- /dev/null +++ b/tests/baselines/reference/jsxAndTypeAssertion.errors.txt @@ -0,0 +1,36 @@ +tests/cases/conformance/jsx/jsxAndTypeAssertion.tsx(2,15): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxAndTypeAssertion.tsx(4,6): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxAndTypeAssertion.tsx(6,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxAndTypeAssertion.tsx(8,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxAndTypeAssertion.tsx(10,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxAndTypeAssertion.tsx(12,1): error TS17005: JSX elements are not currently supported. + + +==== tests/cases/conformance/jsx/jsxAndTypeAssertion.tsx (6 errors) ==== + + { test: }; + ~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + ; + ~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + hello {{}} ; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + {}}>hello; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + {}}>hello{{}}; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + {{/foo/.test(x) ? : }} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + + \ No newline at end of file diff --git a/tests/baselines/reference/jsxAndTypeAssertion.js b/tests/baselines/reference/jsxAndTypeAssertion.js new file mode 100644 index 0000000000000..03972f55782ce --- /dev/null +++ b/tests/baselines/reference/jsxAndTypeAssertion.js @@ -0,0 +1,24 @@ +//// [jsxAndTypeAssertion.tsx] + + { test: }; + +; + +hello {{}} ; + +{}}>hello; + +{}}>hello{{}}; + +{{/foo/.test(x) ? : }} + + + + +//// [jsxAndTypeAssertion.js] +{ test: }; +; +; +; +; +; diff --git a/tests/baselines/reference/jsxClosingTagMapsRelaxingRules.errors.txt b/tests/baselines/reference/jsxClosingTagMapsRelaxingRules.errors.txt new file mode 100644 index 0000000000000..a95a0cabdf803 --- /dev/null +++ b/tests/baselines/reference/jsxClosingTagMapsRelaxingRules.errors.txt @@ -0,0 +1,19 @@ +tests/cases/conformance/jsx/jsxClosingTagMapsRelaxingRules.tsx(1,4): error TS17002: Expected corresponding JSX closing tag for 'a'. +tests/cases/conformance/jsx/jsxClosingTagMapsRelaxingRules.tsx(2,11): error TS17002: Expected corresponding JSX closing tag for 'a'. +tests/cases/conformance/jsx/jsxClosingTagMapsRelaxingRules.tsx(3,12): error TS17002: Expected corresponding JSX closing tag for 'a'. + + +==== tests/cases/conformance/jsx/jsxClosingTagMapsRelaxingRules.tsx (3 errors) ==== +
; + ~~~~ +!!! error TS17002: Expected corresponding JSX closing tag for 'a'. + foo {}; + ~~~~ +!!! error TS17002: Expected corresponding JSX closing tag for 'a'. + foo bar; + ~~~~ +!!! error TS17002: Expected corresponding JSX closing tag for 'a'. + Hello \ No newline at end of file diff --git a/tests/baselines/reference/jsxClosingTagMapsRelaxingRules.js b/tests/baselines/reference/jsxClosingTagMapsRelaxingRules.js new file mode 100644 index 0000000000000..e26469c8af8fd --- /dev/null +++ b/tests/baselines/reference/jsxClosingTagMapsRelaxingRules.js @@ -0,0 +1,14 @@ +//// [jsxClosingTagMapsRelaxingRules.tsx] +; + foo {}; + foo bar; + Hello + +//// [jsxClosingTagMapsRelaxingRules.js] +; +; +; +; diff --git a/tests/baselines/reference/jsxEsprimaFbTestSuite.errors.txt b/tests/baselines/reference/jsxEsprimaFbTestSuite.errors.txt new file mode 100644 index 0000000000000..da0abefc9adcd --- /dev/null +++ b/tests/baselines/reference/jsxEsprimaFbTestSuite.errors.txt @@ -0,0 +1,115 @@ +tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(2,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(8,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(10,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(11,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(14,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(16,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(22,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(24,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(26,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(28,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(30,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(32,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(34,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(36,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(38,2): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(38,13): error TS2304: Cannot find name 'x'. +tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(40,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(42,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(44,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(46,1): error TS17005: JSX elements are not currently supported. + + +==== tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx (20 errors) ==== + + ; + ~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + //; Namespace unsuported + + // {value} ; Namespace unsuported + + ; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + ; + ~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + ; + ~~ +!!! error TS17005: JSX elements are not currently supported. + + <日本語>; + ~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + + ~~~~~~~~~~~~~~~~~~~~~~~ + bar + ~~~ + baz + ~~~ + ; + ~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + : } />; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + {}; + ~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + {/* this is a comment */}; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + +
@test content
; + ~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + +

7x invalid-js-identifier
; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + right=monkeys /> gorillas />; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + ; + ~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + ; + ~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + (
) < x; + ~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + ~ +!!! error TS2304: Cannot find name 'x'. + +
; + ~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + +
; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + +
; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + ; + ~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + \ No newline at end of file diff --git a/tests/baselines/reference/jsxEsprimaFbTestSuite.js b/tests/baselines/reference/jsxEsprimaFbTestSuite.js new file mode 100644 index 0000000000000..22ad42740d70d --- /dev/null +++ b/tests/baselines/reference/jsxEsprimaFbTestSuite.js @@ -0,0 +1,71 @@ +//// [jsxEsprimaFbTestSuite.tsx] + +; + +//; Namespace unsuported + +// {value} ; Namespace unsuported + +; + +; +; + +<日本語>; + + +bar +baz +; + + : } />; + +{}; + +{/* this is a comment */}; + +
@test content
; + +

7x invalid-js-identifier
; + + right=monkeys /> gorillas />; + +; + +; + +(
) < x; + +
; + +
; + +
; + + ; + + +//// [jsxEsprimaFbTestSuite.js] +; +//; Namespace unsuported +// {value} ; Namespace unsuported +; +; +; +; +; +; +; +; +; +; +; +; +; +() < x; +; +; +; +; diff --git a/tests/baselines/reference/jsxInvalidEsprimaTestSuite.errors.txt b/tests/baselines/reference/jsxInvalidEsprimaTestSuite.errors.txt new file mode 100644 index 0000000000000..5ee7c749c8ff8 --- /dev/null +++ b/tests/baselines/reference/jsxInvalidEsprimaTestSuite.errors.txt @@ -0,0 +1,205 @@ +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(2,2): error TS1003: Identifier expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(3,3): error TS1003: Identifier expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(4,2): error TS1003: Identifier expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(5,6): error TS1005: '{' expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(5,9): error TS1109: Expression expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(5,10): error TS1109: Expression expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(6,1): error TS1003: Identifier expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(7,4): error TS17002: Expected corresponding JSX closing tag for 'a'. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(8,13): error TS1002: Unterminated string literal. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(9,1): error TS1003: Identifier expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(9,3): error TS1003: Identifier expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(9,6): error TS17002: Expected corresponding JSX closing tag for 'a'. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(10,3): error TS1003: Identifier expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(10,5): error TS1003: Identifier expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(10,11): error TS1005: '>' expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(11,5): error TS1003: Identifier expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(11,13): error TS1005: '>' expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(12,8): error TS17002: Expected corresponding JSX closing tag for 'a.b.c'. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(13,2): error TS1003: Identifier expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(13,7): error TS1003: Identifier expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(14,4): error TS1003: Identifier expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(14,9): error TS1003: Identifier expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(15,3): error TS1003: Identifier expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(15,12): error TS1005: '>' expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(16,3): error TS1003: Identifier expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(16,14): error TS1005: '>' expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(21,10): error TS1005: '}' expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(21,11): error TS1012: Unexpected token. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(21,13): error TS1003: Identifier expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(21,14): error TS1005: '>' expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(21,14): error TS2304: Cannot find name 'a'. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(21,16): error TS1109: Expression expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(22,20): error TS1003: Identifier expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(23,15): error TS1003: Identifier expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(24,7): error TS1005: '...' expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(26,17): error TS1005: '>' expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(26,18): error TS1109: Expression expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(26,26): error TS1012: Unexpected token. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(26,27): error TS1109: Expression expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(26,28): error TS1109: Expression expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(27,28): error TS1005: '>' expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(27,29): error TS1129: Statement expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(27,32): error TS2304: Cannot find name 'props'. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(27,38): error TS1109: Expression expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(27,39): error TS1109: Expression expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(31,6): error TS1005: '{' expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(32,7): error TS1003: Identifier expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(32,8): error TS1109: Expression expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(32,9): error TS1109: Expression expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(33,2): error TS2304: Cannot find name 'a'. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(33,4): error TS1109: Expression expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(33,6): error TS1003: Identifier expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(33,7): error TS1005: '>' expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(33,7): error TS2304: Cannot find name 'a'. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(33,9): error TS1109: Expression expected. +tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(34,4): error TS1003: Identifier expected. + + +==== tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx (56 errors) ==== + + ; + ~ +!!! error TS1003: Identifier expected. + ; + ~ +!!! error TS1003: Identifier expected. + <:a />; + ~ +!!! error TS1003: Identifier expected. + ; + ~ +!!! error TS1005: '{' expected. + ~ +!!! error TS1109: Expression expected. + ~ +!!! error TS1109: Expression expected. + ; + ~ +!!! error TS1003: Identifier expected. + ; + ~~~~ +!!! error TS17002: Expected corresponding JSX closing tag for 'a'. + ; + ~ +!!! error TS1005: '}' expected. + ~ +!!! error TS1012: Unexpected token. + ~ +!!! error TS1003: Identifier expected. + ~ +!!! error TS1005: '>' expected. + ~ +!!! error TS2304: Cannot find name 'a'. + ~ +!!! error TS1109: Expression expected. + ; + ~ +!!! error TS1003: Identifier expected. +
; + ~~~~~ +!!! error TS1003: Identifier expected. +
; + ~~~~~ +!!! error TS1005: '...' expected. + +
stuff
; + ~ +!!! error TS1005: '>' expected. + ~~~ +!!! error TS1109: Expression expected. + ~ +!!! error TS1012: Unexpected token. + ~ +!!! error TS1109: Expression expected. + ~ +!!! error TS1109: Expression expected. +
stuff
; + ~ +!!! error TS1005: '>' expected. + ~~~ +!!! error TS1129: Statement expected. + ~~~~~ +!!! error TS2304: Cannot find name 'props'. + ~ +!!! error TS1109: Expression expected. + ~ +!!! error TS1109: Expression expected. + +
>; + >; + ; + ~ +!!! error TS1005: '{' expected. + ; + ~ +!!! error TS1003: Identifier expected. + ~ +!!! error TS1109: Expression expected. + ~ +!!! error TS1109: Expression expected. + }; + ~ +!!! error TS2304: Cannot find name 'a'. + ~ +!!! error TS1109: Expression expected. + ~ +!!! error TS1003: Identifier expected. + ~ +!!! error TS1005: '>' expected. + ~ +!!! error TS2304: Cannot find name 'a'. + ~ +!!! error TS1109: Expression expected. + ; + ~~~ +!!! error TS1003: Identifier expected. \ No newline at end of file diff --git a/tests/baselines/reference/jsxInvalidEsprimaTestSuite.js b/tests/baselines/reference/jsxInvalidEsprimaTestSuite.js new file mode 100644 index 0000000000000..04ff436f8b45f --- /dev/null +++ b/tests/baselines/reference/jsxInvalidEsprimaTestSuite.js @@ -0,0 +1,59 @@ +//// [jsxInvalidEsprimaTestSuite.tsx] + +; +; +<:a />; +; +; +; +; +; +
; +
; + +
stuff
; +
stuff
; + +
>; + >; +; +; +}; +; + +//// [jsxInvalidEsprimaTestSuite.js] +; +; +; +; +; +a > ; +; +; + > ; +; +{ + props; +} + > ; +; +; +; + > ; +; +; +a > ; +; diff --git a/tests/baselines/reference/jsxReactApp.errors.txt b/tests/baselines/reference/jsxReactApp.errors.txt new file mode 100644 index 0000000000000..8c86aa0947707 --- /dev/null +++ b/tests/baselines/reference/jsxReactApp.errors.txt @@ -0,0 +1,212 @@ +tests/cases/compiler/jsxReactApp.tsx(163,17): error TS17005: JSX elements are not currently supported. +tests/cases/compiler/jsxReactApp.tsx(185,13): error TS17005: JSX elements are not currently supported. + + +==== tests/cases/compiler/jsxReactApp.tsx (2 errors) ==== + declare module React { + + interface ComponentClass

{ + new(props: any): Component; + prototype: { props: P }; + } + + interface ReactCompositeElement

{ + type: ComponentClass

; + props?: P; + key?: number | string; + ref?: string; + } + + interface ReactHtmlElement { + type: string; + props?: ReactAttributes; + key?: number | string; + ref?: string; + } + + type ReactElement = ReactCompositeElement | ReactHtmlElement; + + interface ReactElementArray extends Array { + + } + + class Component

{ + constructor(props: P, childen?: any[]); + + props: P; + state: S; + + setState(state: S, callback?: () => void): void + render(): ReactElement; + } + + interface ReactAttributes { + children?: ReactElementArray; + key?: number | string; + ref?: string; + + // Event Attributes + + dangerouslySetInnerHTML?: { + __html: string; + }; + } + + interface HTMLAttributes extends ReactAttributes { + accept?: string; + acceptCharset?: string; + accessKey?: string; + action?: string; + allowFullScreen?: boolean; + allowTransparency?: boolean; + alt?: string; + async?: boolean; + autoComplete?: boolean; + autoFocus?: boolean; + autoPlay?: boolean; + cellPadding?: number | string; + cellSpacing?: number | string; + charSet?: string; + checked?: boolean; + classID?: string; + className?: string; + cols?: number; + colSpan?: number; + content?: string; + contentEditable?: boolean; + contextMenu?: string; + controls?: any; + coords?: string; + crossOrigin?: string; + data?: string; + dateTime?: string; + defer?: boolean; + dir?: string; + disabled?: boolean; + download?: any; + draggable?: boolean; + encType?: string; + form?: string; + formNoValidate?: boolean; + frameBorder?: number | string; + height?: number | string; + hidden?: boolean; + href?: string; + hrefLang?: string; + htmlFor?: string; + httpEquiv?: string; + icon?: string; + id?: string; + label?: string; + lang?: string; + list?: string; + loop?: boolean; + manifest?: string; + max?: number | string; + maxLength?: number; + media?: string; + mediaGroup?: string; + method?: string; + min?: number | string; + multiple?: boolean; + muted?: boolean; + name?: string; + noValidate?: boolean; + open?: boolean; + pattern?: string; + placeholder?: string; + poster?: string; + preload?: string; + radioGroup?: string; + readOnly?: boolean; + rel?: string; + required?: boolean; + role?: string; + rows?: number; + rowSpan?: number; + sandbox?: string; + scope?: string; + scrollLeft?: number; + scrolling?: string; + scrollTop?: number; + seamless?: boolean; + selected?: boolean; + shape?: string; + size?: number; + sizes?: string; + span?: number; + spellCheck?: boolean; + src?: string; + srcDoc?: string; + srcSet?: string; + start?: number; + step?: number | string; + tabIndex?: number; + target?: string; + title?: string; + type?: string; + useMap?: string; + value?: string; + width?: number | string; + wmode?: string; + + // Non-standard Attributes + autoCapitalize?: boolean; + autoCorrect?: boolean; + property?: string; + itemProp?: string; + itemScope?: boolean; + itemType?: string; + } + + function createElement(type: string, props?: HTMLAttributes, ...rest: any[]): ReactHtmlElement; + function createElement

(type: ComponentClass

, props?: P, ...rest: any[]): ReactCompositeElement

; + } + + class TodoList extends React.Component<{ items: string[] },{}> { + render(): React.ReactElement { + return

    {this.props.items.map(itemText =>
  • {itemText}
  • )}
; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + } + } + + class TodoApp extends React.Component<{},{items?: string[]; text?: string}> { + state = {items: [], text: ''}; + + onChange = (e: any) => { + this.setState({ + text: e.target.value + }); + } + + handleSubmit = (e: any) => { + e.preventDefault(); + var nextItems = this.state.items.concat([this.state.text]); + var nextText = ''; + this.setState({items: nextItems, text: nextText}); + } + + render(): React.ReactElement { + return ( +
+ ~~~~~ +

TODO

+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +
+ ~~~~~~~~~~~~~~~~~~~~~~~ +
+ ~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + ); + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/jsxReactApp.js b/tests/baselines/reference/jsxReactApp.js new file mode 100644 index 0000000000000..5ce192d6257f4 --- /dev/null +++ b/tests/baselines/reference/jsxReactApp.js @@ -0,0 +1,238 @@ +//// [jsxReactApp.tsx] +declare module React { + + interface ComponentClass

{ + new(props: any): Component; + prototype: { props: P }; + } + + interface ReactCompositeElement

{ + type: ComponentClass

; + props?: P; + key?: number | string; + ref?: string; + } + + interface ReactHtmlElement { + type: string; + props?: ReactAttributes; + key?: number | string; + ref?: string; + } + + type ReactElement = ReactCompositeElement | ReactHtmlElement; + + interface ReactElementArray extends Array { + + } + + class Component

{ + constructor(props: P, childen?: any[]); + + props: P; + state: S; + + setState(state: S, callback?: () => void): void + render(): ReactElement; + } + + interface ReactAttributes { + children?: ReactElementArray; + key?: number | string; + ref?: string; + + // Event Attributes + + dangerouslySetInnerHTML?: { + __html: string; + }; + } + + interface HTMLAttributes extends ReactAttributes { + accept?: string; + acceptCharset?: string; + accessKey?: string; + action?: string; + allowFullScreen?: boolean; + allowTransparency?: boolean; + alt?: string; + async?: boolean; + autoComplete?: boolean; + autoFocus?: boolean; + autoPlay?: boolean; + cellPadding?: number | string; + cellSpacing?: number | string; + charSet?: string; + checked?: boolean; + classID?: string; + className?: string; + cols?: number; + colSpan?: number; + content?: string; + contentEditable?: boolean; + contextMenu?: string; + controls?: any; + coords?: string; + crossOrigin?: string; + data?: string; + dateTime?: string; + defer?: boolean; + dir?: string; + disabled?: boolean; + download?: any; + draggable?: boolean; + encType?: string; + form?: string; + formNoValidate?: boolean; + frameBorder?: number | string; + height?: number | string; + hidden?: boolean; + href?: string; + hrefLang?: string; + htmlFor?: string; + httpEquiv?: string; + icon?: string; + id?: string; + label?: string; + lang?: string; + list?: string; + loop?: boolean; + manifest?: string; + max?: number | string; + maxLength?: number; + media?: string; + mediaGroup?: string; + method?: string; + min?: number | string; + multiple?: boolean; + muted?: boolean; + name?: string; + noValidate?: boolean; + open?: boolean; + pattern?: string; + placeholder?: string; + poster?: string; + preload?: string; + radioGroup?: string; + readOnly?: boolean; + rel?: string; + required?: boolean; + role?: string; + rows?: number; + rowSpan?: number; + sandbox?: string; + scope?: string; + scrollLeft?: number; + scrolling?: string; + scrollTop?: number; + seamless?: boolean; + selected?: boolean; + shape?: string; + size?: number; + sizes?: string; + span?: number; + spellCheck?: boolean; + src?: string; + srcDoc?: string; + srcSet?: string; + start?: number; + step?: number | string; + tabIndex?: number; + target?: string; + title?: string; + type?: string; + useMap?: string; + value?: string; + width?: number | string; + wmode?: string; + + // Non-standard Attributes + autoCapitalize?: boolean; + autoCorrect?: boolean; + property?: string; + itemProp?: string; + itemScope?: boolean; + itemType?: string; + } + + function createElement(type: string, props?: HTMLAttributes, ...rest: any[]): ReactHtmlElement; + function createElement

(type: ComponentClass

, props?: P, ...rest: any[]): ReactCompositeElement

; +} + +class TodoList extends React.Component<{ items: string[] },{}> { + render(): React.ReactElement { + return

    {this.props.items.map(itemText =>
  • {itemText}
  • )}
; + } +} + +class TodoApp extends React.Component<{},{items?: string[]; text?: string}> { + state = {items: [], text: ''}; + + onChange = (e: any) => { + this.setState({ + text: e.target.value + }); + } + + handleSubmit = (e: any) => { + e.preventDefault(); + var nextItems = this.state.items.concat([this.state.text]); + var nextText = ''; + this.setState({items: nextItems, text: nextText}); + } + + render(): React.ReactElement { + return ( +
+

TODO

+ +
+ + +
+
+ ); + } +} + + +//// [jsxReactApp.js] +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var TodoList = (function (_super) { + __extends(TodoList, _super); + function TodoList() { + _super.apply(this, arguments); + } + TodoList.prototype.render = function () { + return ; + }; + return TodoList; +})(React.Component); +var TodoApp = (function (_super) { + __extends(TodoApp, _super); + function TodoApp() { + var _this = this; + _super.apply(this, arguments); + this.state = { items: [], text: '' }; + this.onChange = function (e) { + _this.setState({ + text: e.target.value + }); + }; + this.handleSubmit = function (e) { + e.preventDefault(); + var nextItems = _this.state.items.concat([_this.state.text]); + var nextText = ''; + _this.setState({ items: nextItems, text: nextText }); + }; + } + TodoApp.prototype.render = function () { + return (); + }; + return TodoApp; +})(React.Component); diff --git a/tests/baselines/reference/jsxReactTestSuite.errors.txt b/tests/baselines/reference/jsxReactTestSuite.errors.txt new file mode 100644 index 0000000000000..d5e94dc20d009 --- /dev/null +++ b/tests/baselines/reference/jsxReactTestSuite.errors.txt @@ -0,0 +1,225 @@ +tests/cases/conformance/jsx/jsxReactTestSuite.tsx(1,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxReactTestSuite.tsx(3,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxReactTestSuite.tsx(7,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxReactTestSuite.tsx(14,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxReactTestSuite.tsx(18,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxReactTestSuite.tsx(23,3): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxReactTestSuite.tsx(41,3): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxReactTestSuite.tsx(55,3): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxReactTestSuite.tsx(65,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxReactTestSuite.tsx(67,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxReactTestSuite.tsx(69,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxReactTestSuite.tsx(71,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxReactTestSuite.tsx(73,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxReactTestSuite.tsx(75,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxReactTestSuite.tsx(77,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxReactTestSuite.tsx(80,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxReactTestSuite.tsx(83,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxReactTestSuite.tsx(85,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxReactTestSuite.tsx(87,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxReactTestSuite.tsx(89,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxReactTestSuite.tsx(91,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxReactTestSuite.tsx(93,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxReactTestSuite.tsx(95,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxReactTestSuite.tsx(98,1): error TS17005: JSX elements are not currently supported. +tests/cases/conformance/jsx/jsxReactTestSuite.tsx(100,1): error TS17005: JSX elements are not currently supported. + + +==== tests/cases/conformance/jsx/jsxReactTestSuite.tsx (25 errors) ==== +
text
; + ~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + +
+ ~~~~~ + {this.props.children} + ~~~~~~~~~~~~~~~~~~~~~~~ +
; + ~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + +
+ ~~~~~ +

+ ~~~~~~~~~~~~~~~~~~~ + {foo}
{bar}
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +
+ ~~~~~~~~ +
; + ~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + + + ~~~~~~~~~~~ + {this.props.children} + ~~~~~~~~~~~~~~~~~~~~~~~~~ + ; + ~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + + ~~~~~~~~~~~ + + ~~~~~~~~~~~~~~~~~~ + ; + ~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + var x = +
+ ~~~~~~~~~~~~~~~~ +
; + ~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + ( +
+ ~~~~~ + {/* A comment at the beginning */} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + {/* A second comment at the beginning */} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + ~~~~~~~~~~ + {/* A nested comment */} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + ~~~~~~~~~~~ + {/* A sandwiched comment */} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +
+ ~~~~~~~~~~ + {/* A comment at the end */} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + {/* A second comment at the end */} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +
+ ~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + ); + + ( +
+ ~~~~~~~~~~~~~~~~ + + ~~~~~~ +
+ ~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + ); + +
 
; + ~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + +
 
; + ~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + testing; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + ; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + ; + ~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + ; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + ; + ~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + ; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + ; + ~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + ; + ~~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + ; + ~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + ; + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + ; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + ; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + ; + ~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + + ; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + Text; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS17005: JSX elements are not currently supported. + + + \ No newline at end of file diff --git a/tests/baselines/reference/jsxReactTestSuite.js b/tests/baselines/reference/jsxReactTestSuite.js new file mode 100644 index 0000000000000..cb41d1aca1371 --- /dev/null +++ b/tests/baselines/reference/jsxReactTestSuite.js @@ -0,0 +1,131 @@ +//// [jsxReactTestSuite.tsx] +
text
; + +
+ {this.props.children} +
; + +
+

+ {foo}
{bar}
+
+
; + + + + {this.props.children} +; + + + +; + +var x = +
+
; + +( +
+ {/* A comment at the beginning */} + {/* A second comment at the beginning */} + + {/* A nested comment */} + + {/* A sandwiched comment */} +
+ {/* A comment at the end */} + {/* A second comment at the end */} +
+); + +( +
+ +
+); + +
 
; + +
 
; + +testing; + +; + +; + +; + +; + +; + +; + +; + +; + +; + +; + +; + +; + + +; + +Text; + + + + +//// [jsxReactTestSuite.js] +; +; +; +; +; +var x = ; +(); +(); +; +; +; +; +; +; +; +; +; +; +; +; +; +; +; +; +; diff --git a/tests/baselines/reference/project/invalidRootFile/amd/invalidRootFile.errors.txt b/tests/baselines/reference/project/invalidRootFile/amd/invalidRootFile.errors.txt index 1bda32a0b4cfc..8dfc3b6e5ad34 100644 --- a/tests/baselines/reference/project/invalidRootFile/amd/invalidRootFile.errors.txt +++ b/tests/baselines/reference/project/invalidRootFile/amd/invalidRootFile.errors.txt @@ -1,6 +1,6 @@ -error TS6054: File 'a.t' has unsupported extension. The only supported extensions are '.ts', '.d.ts'. +error TS6054: File 'a.t' has unsupported extension. The only supported extensions are '.tsx', '.ts', '.d.ts'. error TS6053: File 'a.ts' not found. -!!! error TS6054: File 'a.t' has unsupported extension. The only supported extensions are '.ts', '.d.ts'. +!!! error TS6054: File 'a.t' has unsupported extension. The only supported extensions are '.tsx', '.ts', '.d.ts'. !!! error TS6053: File 'a.ts' not found. \ No newline at end of file diff --git a/tests/baselines/reference/project/invalidRootFile/node/invalidRootFile.errors.txt b/tests/baselines/reference/project/invalidRootFile/node/invalidRootFile.errors.txt index 1bda32a0b4cfc..8dfc3b6e5ad34 100644 --- a/tests/baselines/reference/project/invalidRootFile/node/invalidRootFile.errors.txt +++ b/tests/baselines/reference/project/invalidRootFile/node/invalidRootFile.errors.txt @@ -1,6 +1,6 @@ -error TS6054: File 'a.t' has unsupported extension. The only supported extensions are '.ts', '.d.ts'. +error TS6054: File 'a.t' has unsupported extension. The only supported extensions are '.tsx', '.ts', '.d.ts'. error TS6053: File 'a.ts' not found. -!!! error TS6054: File 'a.t' has unsupported extension. The only supported extensions are '.ts', '.d.ts'. +!!! error TS6054: File 'a.t' has unsupported extension. The only supported extensions are '.tsx', '.ts', '.d.ts'. !!! error TS6053: File 'a.ts' not found. \ No newline at end of file