diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 28b664a33e4af..d2b2e050ea551 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10795,13 +10795,24 @@ namespace ts { checkGrammarJsxElement(node); checkJsxPreconditions(node); - // The reactNamespace symbol should be marked as 'used' so we don't incorrectly elide its import. And if there - // is no reactNamespace symbol in scope when targeting React emit, we should issue an error. - const reactRefErr = compilerOptions.jsx === JsxEmit.React ? Diagnostics.Cannot_find_name_0 : undefined; - const reactNamespace = compilerOptions.reactNamespace ? compilerOptions.reactNamespace : "React"; - const reactSym = resolveName(node.tagName, reactNamespace, SymbolFlags.Value, reactRefErr, reactNamespace); - if (reactSym) { - getSymbolLinks(reactSym).referenced = true; + // The JSX factory namespace symbol should be marked as 'used' so we don't incorrectly elide its import. And if + // it isn't in scope when targeting React emit, we should issue an error. + const jsxFactoryRefErr = compilerOptions.jsx === JsxEmit.React ? Diagnostics.Cannot_find_name_0 : undefined; + let jsxFactoryNamespace = "React"; + if (compilerOptions.jsxFactory) { + let { entityName } = parseIsolatedEntityName(compilerOptions.jsxFactory); + while (entityName.kind === SyntaxKind.QualifiedName) { + entityName = (entityName).left; + } + Debug.assertNode(entityName, node => node.kind === SyntaxKind.Identifier); + jsxFactoryNamespace = (entityName).text; + } + else if (compilerOptions.reactNamespace) { + jsxFactoryNamespace = compilerOptions.reactNamespace; + } + const jsxFactorySym = resolveName(node.tagName, jsxFactoryNamespace, SymbolFlags.Value, jsxFactoryRefErr, jsxFactoryNamespace); + if (jsxFactorySym) { + getSymbolLinks(jsxFactorySym).referenced = true; } const targetAttributesType = getJsxElementAttributesType(node); diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 648447ac26ac4..5f7297ae99876 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -72,6 +72,11 @@ namespace ts { paramType: Diagnostics.KIND, description: Diagnostics.Specify_JSX_code_generation_Colon_preserve_or_react, }, + { + name: "jsxFactory", + type: "string", + description: Diagnostics.Specify_the_JSX_factory_function_to_use_when_targeting_react_JSX_emit_e_g_React_createElement_or_h, + }, { name: "reactNamespace", type: "string", diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 71d7a978d1ba0..eafb191535c82 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2365,6 +2365,14 @@ "category": "Error", "code": 5066 }, + "Option '{0}' can only be used when '{1}' is '{2}'.": { + "category": "Error", + "code": 5067 + }, + "Invalid value for '{0}'. '{1}' is not a valid identifier/qualified-name.": { + "category": "Error", + "code": 5068 + }, "Concatenate and emit output to single file.": { "category": "Message", "code": 6001 @@ -2861,6 +2869,10 @@ "category": "Error", "code": 6140 }, + "Specify the JSX factory function to use when targeting 'react' JSX emit, e.g. 'React.createElement' or 'h'.": { + "category": "Message", + "code": 6141 + }, "Variable '{0}' implicitly has an '{1}' type.": { "category": "Error", "code": 7005 diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index d873c3ef87777..7572df79ce940 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -1618,17 +1618,38 @@ namespace ts { ); } - function createReactNamespace(reactNamespace: string, parent: JsxOpeningLikeElement) { + export function createEntityName(entityName: string) { + const { entityName: node } = parseIsolatedEntityName(entityName); + + // Parsing occurred in an isolated context, so nodes need to be synthesized + // and positions erased for correct positioning in emit. + const synthesize = (node: Node) => { + node.pos = -1; + node.end = -1; + node.flags |= NodeFlags.Synthesized; + forEachChild(node, synthesize); + }; + synthesize(node); + + return node; + } + + export function createJsxFactory(jsxFactory: string) { + const entityName = createEntityName(jsxFactory); + return createExpressionFromEntityName(entityName); + } + + export function createReactCreateElement(reactNamespace: string | undefined, parentElement: JsxOpeningLikeElement) { // 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. const react = createIdentifier(reactNamespace || "React"); react.flags &= ~NodeFlags.Synthesized; - react.parent = parent; - return react; + react.parent = parentElement; + return createPropertyAccess(react, "createElement"); } - export function createReactCreateElement(reactNamespace: string, tagName: Expression, props: Expression, children: Expression[], parentElement: JsxOpeningLikeElement, location: TextRange): LeftHandSideExpression { + export function createJsxFactoryCall(jsxFactory: Expression, tagName: Expression, props: Expression, children: Expression[], parentElement: JsxOpeningLikeElement, location: TextRange): LeftHandSideExpression { const argumentsList = [tagName]; if (props) { argumentsList.push(props); @@ -1651,10 +1672,7 @@ namespace ts { } return createCall( - createPropertyAccess( - createReactNamespace(reactNamespace, parentElement), - "createElement" - ), + jsxFactory, /*typeArguments*/ undefined, argumentsList, location @@ -2909,4 +2927,4 @@ namespace ts { function tryGetModuleNameFromDeclaration(declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration, host: EmitHost, resolver: EmitResolver, compilerOptions: CompilerOptions) { return tryGetModuleNameFromFile(resolver.getExternalModuleFileFromDeclaration(declaration), host, compilerOptions); } -} \ No newline at end of file +} diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 9bd9311b74921..3d04b13a44b1b 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -462,6 +462,13 @@ namespace ts { return result; } + /* @internal */ + export function parseIsolatedEntityName(content: string) { + const result = Parser.parseIsolatedEntityName(content); + Parser.fixupParentReferences(result.entityName); + return result; + } + /* @internal */ // Exposed only for testing. export function parseJSDocTypeExpressionForTests(content: string, start?: number, length?: number) { @@ -584,6 +591,20 @@ namespace ts { return result; } + export function parseIsolatedEntityName(content: string, allowReservedWords = false) { + initializeState("file.js", content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS); + sourceFile = { languageVariant: LanguageVariant.Standard, text: content }; + + nextToken(); + const entityName = parseEntityName(allowReservedWords); + parseExpected(SyntaxKind.EndOfFileToken); + + const diagnostics = parseDiagnostics; + clearState(); + + return { entityName, diagnostics }; + } + function getLanguageVariant(scriptKind: ScriptKind) { // .tsx and .jsx files are treated as jsx language variant. return scriptKind === ScriptKind.TSX || scriptKind === ScriptKind.JSX || scriptKind === ScriptKind.JS ? LanguageVariant.JSX : LanguageVariant.Standard; diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 91adb09c402ea..ca341e9d1d080 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1533,6 +1533,21 @@ namespace ts { programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Invalid_value_for_reactNamespace_0_is_not_a_valid_identifier, options.reactNamespace)); } + if (options.jsxFactory) { + if (options.jsx !== JsxEmit.React) { + programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_can_only_be_used_when_1_is_2, "jsxFactory", "jsx", "react")); + } + + if (options.reactNamespace) { + programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "jsxFactory", "reactNamespace")); + } + + const { diagnostics } = parseIsolatedEntityName(options.jsxFactory); + if (diagnostics.length > 0) { + programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Invalid_value_for_0_1_is_not_a_valid_identifier_Slashqualified_name, "jsxFactory", options.jsxFactory)); + } + } + // If the emit is enabled make sure that every output file is unique and not overwriting any of the input files if (!options.noEmit && !options.suppressOutputPathCheck) { const emitHost = getEmitHost(); diff --git a/src/compiler/transformers/jsx.ts b/src/compiler/transformers/jsx.ts index 95a4016bb0aeb..c86ed844328b6 100644 --- a/src/compiler/transformers/jsx.ts +++ b/src/compiler/transformers/jsx.ts @@ -113,8 +113,12 @@ namespace ts { || createAssignHelper(currentSourceFile.externalHelpersModuleName, segments); } - const element = createReactCreateElement( - compilerOptions.reactNamespace, + const jsxFactory = compilerOptions.jsxFactory + ? createJsxFactory(compilerOptions.jsxFactory) + : createReactCreateElement(compilerOptions.reactNamespace, node); + + const element = createJsxFactoryCall( + jsxFactory, tagName, objectProperties, filter(map(children, transformJsxChildToExpression), isDefined), diff --git a/src/compiler/types.ts b/src/compiler/types.ts index f6d791769925e..f0e2fb6dccee4 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2719,6 +2719,7 @@ namespace ts { inlineSources?: boolean; isolatedModules?: boolean; jsx?: JsxEmit; + jsxFactory?: string; lib?: string[]; /*@internal*/listEmittedFiles?: boolean; /*@internal*/listFiles?: boolean; diff --git a/src/harness/unittests/transpile.ts b/src/harness/unittests/transpile.ts index 808a5df37c15d..8ebaadcd63952 100644 --- a/src/harness/unittests/transpile.ts +++ b/src/harness/unittests/transpile.ts @@ -293,6 +293,10 @@ var x = 0;`, { options: { compilerOptions: { jsx: 1 }, fileName: "input.js", reportDiagnostics: true } }); + transpilesCorrectly("Supports setting 'jsxFactory'", "x;", { + options: { compilerOptions: { jsxFactory: "React.createElement", jsx: JsxEmit.React }, fileName: "input.js", reportDiagnostics: true } + }); + transpilesCorrectly("Supports setting 'lib'", "x;", { options: { compilerOptions: { lib: ["es2015", "dom"] }, fileName: "input.js", reportDiagnostics: true } }); diff --git a/tests/baselines/reference/transpile/Supports setting jsxFactory.js b/tests/baselines/reference/transpile/Supports setting jsxFactory.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting jsxFactory.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/tsxReactEmitJsxFactory1.errors.txt b/tests/baselines/reference/tsxReactEmitJsxFactory1.errors.txt new file mode 100644 index 0000000000000..b5f213b35077b --- /dev/null +++ b/tests/baselines/reference/tsxReactEmitJsxFactory1.errors.txt @@ -0,0 +1,15 @@ +tests/cases/conformance/jsx/file.tsx(8,2): error TS2304: Cannot find name 'h'. + + +==== tests/cases/conformance/jsx/file.tsx (1 errors) ==== + declare module JSX { + interface IntrinsicElements { + [s: string]: any; + } + } + + // This should issue an error as 'h' is not declared. +
; + ~~~ +!!! error TS2304: Cannot find name 'h'. + \ No newline at end of file diff --git a/tests/baselines/reference/tsxReactEmitJsxFactory1.js b/tests/baselines/reference/tsxReactEmitJsxFactory1.js new file mode 100644 index 0000000000000..dad37460ecda0 --- /dev/null +++ b/tests/baselines/reference/tsxReactEmitJsxFactory1.js @@ -0,0 +1,14 @@ +//// [file.tsx] +declare module JSX { + interface IntrinsicElements { + [s: string]: any; + } +} + +// This should issue an error as 'h' is not declared. +
; + + +//// [file.js] +// This should issue an error as 'h' is not declared. +h("div", null); diff --git a/tests/baselines/reference/tsxReactEmitJsxFactory2.js b/tests/baselines/reference/tsxReactEmitJsxFactory2.js new file mode 100644 index 0000000000000..054882fd054b4 --- /dev/null +++ b/tests/baselines/reference/tsxReactEmitJsxFactory2.js @@ -0,0 +1,14 @@ +//// [file.tsx] +declare module JSX { + interface IntrinsicElements { + [s: string]: any; + } +} + +declare var h: any; + +
; + + +//// [file.js] +h("div", null); diff --git a/tests/baselines/reference/tsxReactEmitJsxFactory2.symbols b/tests/baselines/reference/tsxReactEmitJsxFactory2.symbols new file mode 100644 index 0000000000000..c3ad64d877abf --- /dev/null +++ b/tests/baselines/reference/tsxReactEmitJsxFactory2.symbols @@ -0,0 +1,18 @@ +=== tests/cases/conformance/jsx/file.tsx === +declare module JSX { +>JSX : Symbol(JSX, Decl(file.tsx, 0, 0)) + + interface IntrinsicElements { +>IntrinsicElements : Symbol(IntrinsicElements, Decl(file.tsx, 0, 20)) + + [s: string]: any; +>s : Symbol(s, Decl(file.tsx, 2, 3)) + } +} + +declare var h: any; +>h : Symbol(h, Decl(file.tsx, 6, 11)) + +
; +>div : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 0, 20)) + diff --git a/tests/baselines/reference/tsxReactEmitJsxFactory2.types b/tests/baselines/reference/tsxReactEmitJsxFactory2.types new file mode 100644 index 0000000000000..a95f3e323b26f --- /dev/null +++ b/tests/baselines/reference/tsxReactEmitJsxFactory2.types @@ -0,0 +1,19 @@ +=== tests/cases/conformance/jsx/file.tsx === +declare module JSX { +>JSX : any + + interface IntrinsicElements { +>IntrinsicElements : IntrinsicElements + + [s: string]: any; +>s : string + } +} + +declare var h: any; +>h : any + +
; +>
: any +>div : any + diff --git a/tests/baselines/reference/tsxReactEmitJsxFactory3.js b/tests/baselines/reference/tsxReactEmitJsxFactory3.js new file mode 100644 index 0000000000000..ef261a9b6152c --- /dev/null +++ b/tests/baselines/reference/tsxReactEmitJsxFactory3.js @@ -0,0 +1,14 @@ +//// [file.tsx] +declare module JSX { + interface IntrinsicElements { + [s: string]: any; + } +} + +declare var React: any; + +
; + + +//// [file.js] +React.createElement("div", null); diff --git a/tests/baselines/reference/tsxReactEmitJsxFactory3.symbols b/tests/baselines/reference/tsxReactEmitJsxFactory3.symbols new file mode 100644 index 0000000000000..6c499aea616f3 --- /dev/null +++ b/tests/baselines/reference/tsxReactEmitJsxFactory3.symbols @@ -0,0 +1,18 @@ +=== tests/cases/conformance/jsx/file.tsx === +declare module JSX { +>JSX : Symbol(JSX, Decl(file.tsx, 0, 0)) + + interface IntrinsicElements { +>IntrinsicElements : Symbol(IntrinsicElements, Decl(file.tsx, 0, 20)) + + [s: string]: any; +>s : Symbol(s, Decl(file.tsx, 2, 3)) + } +} + +declare var React: any; +>React : Symbol(React, Decl(file.tsx, 6, 11)) + +
; +>div : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 0, 20)) + diff --git a/tests/baselines/reference/tsxReactEmitJsxFactory3.types b/tests/baselines/reference/tsxReactEmitJsxFactory3.types new file mode 100644 index 0000000000000..e7a87602da263 --- /dev/null +++ b/tests/baselines/reference/tsxReactEmitJsxFactory3.types @@ -0,0 +1,19 @@ +=== tests/cases/conformance/jsx/file.tsx === +declare module JSX { +>JSX : any + + interface IntrinsicElements { +>IntrinsicElements : IntrinsicElements + + [s: string]: any; +>s : string + } +} + +declare var React: any; +>React : any + +
; +>
: any +>div : any + diff --git a/tests/baselines/reference/tsxReactEmitJsxFactory4.js b/tests/baselines/reference/tsxReactEmitJsxFactory4.js new file mode 100644 index 0000000000000..278c2ca345976 --- /dev/null +++ b/tests/baselines/reference/tsxReactEmitJsxFactory4.js @@ -0,0 +1,14 @@ +//// [file.tsx] +declare module JSX { + interface IntrinsicElements { + [s: string]: any; + } +} + +declare var a: any; + +
; + + +//// [file.js] +a.b.c("div", null); diff --git a/tests/baselines/reference/tsxReactEmitJsxFactory4.symbols b/tests/baselines/reference/tsxReactEmitJsxFactory4.symbols new file mode 100644 index 0000000000000..cae9d4eeb1c86 --- /dev/null +++ b/tests/baselines/reference/tsxReactEmitJsxFactory4.symbols @@ -0,0 +1,18 @@ +=== tests/cases/conformance/jsx/file.tsx === +declare module JSX { +>JSX : Symbol(JSX, Decl(file.tsx, 0, 0)) + + interface IntrinsicElements { +>IntrinsicElements : Symbol(IntrinsicElements, Decl(file.tsx, 0, 20)) + + [s: string]: any; +>s : Symbol(s, Decl(file.tsx, 2, 3)) + } +} + +declare var a: any; +>a : Symbol(a, Decl(file.tsx, 6, 11)) + +
; +>div : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 0, 20)) + diff --git a/tests/baselines/reference/tsxReactEmitJsxFactory4.types b/tests/baselines/reference/tsxReactEmitJsxFactory4.types new file mode 100644 index 0000000000000..176d907a6f7d1 --- /dev/null +++ b/tests/baselines/reference/tsxReactEmitJsxFactory4.types @@ -0,0 +1,19 @@ +=== tests/cases/conformance/jsx/file.tsx === +declare module JSX { +>JSX : any + + interface IntrinsicElements { +>IntrinsicElements : IntrinsicElements + + [s: string]: any; +>s : string + } +} + +declare var a: any; +>a : any + +
; +>
: any +>div : any + diff --git a/tests/baselines/reference/tsxReactEmitJsxFactory5.js b/tests/baselines/reference/tsxReactEmitJsxFactory5.js new file mode 100644 index 0000000000000..f12a25e4e4fce --- /dev/null +++ b/tests/baselines/reference/tsxReactEmitJsxFactory5.js @@ -0,0 +1,24 @@ +//// [tests/cases/conformance/jsx/tsxReactEmitJsxFactory5.tsx] //// + +//// [file.tsx] +declare module JSX { + interface IntrinsicElements { + [s: string]: any; + } +} + +//// [h.d.ts] +export var h; + +//// [react-consumer.tsx] +import {h} from "./h"; +// Should not elide h import +
; + + +//// [file.js] +//// [react-consumer.js] +"use strict"; +var h_1 = require("./h"); +// Should not elide h import +h("div", null); diff --git a/tests/baselines/reference/tsxReactEmitJsxFactory5.symbols b/tests/baselines/reference/tsxReactEmitJsxFactory5.symbols new file mode 100644 index 0000000000000..b8bdf5772bd8c --- /dev/null +++ b/tests/baselines/reference/tsxReactEmitJsxFactory5.symbols @@ -0,0 +1,24 @@ +=== tests/cases/conformance/jsx/file.tsx === +declare module JSX { +>JSX : Symbol(JSX, Decl(file.tsx, 0, 0)) + + interface IntrinsicElements { +>IntrinsicElements : Symbol(IntrinsicElements, Decl(file.tsx, 0, 20)) + + [s: string]: any; +>s : Symbol(s, Decl(file.tsx, 2, 3)) + } +} + +=== tests/cases/conformance/jsx/h.d.ts === +export var h; +>h : Symbol(h, Decl(h.d.ts, 0, 10)) + +=== tests/cases/conformance/jsx/react-consumer.tsx === +import {h} from "./h"; +>h : Symbol(h, Decl(react-consumer.tsx, 0, 8)) + +// Should not elide h import +
; +>div : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 0, 20)) + diff --git a/tests/baselines/reference/tsxReactEmitJsxFactory5.types b/tests/baselines/reference/tsxReactEmitJsxFactory5.types new file mode 100644 index 0000000000000..2c8cddf4ac3bc --- /dev/null +++ b/tests/baselines/reference/tsxReactEmitJsxFactory5.types @@ -0,0 +1,25 @@ +=== tests/cases/conformance/jsx/file.tsx === +declare module JSX { +>JSX : any + + interface IntrinsicElements { +>IntrinsicElements : IntrinsicElements + + [s: string]: any; +>s : string + } +} + +=== tests/cases/conformance/jsx/h.d.ts === +export var h; +>h : any + +=== tests/cases/conformance/jsx/react-consumer.tsx === +import {h} from "./h"; +>h : any + +// Should not elide h import +
; +>
: any +>div : any + diff --git a/tests/baselines/reference/tsxReactEmitJsxFactory6.errors.txt b/tests/baselines/reference/tsxReactEmitJsxFactory6.errors.txt new file mode 100644 index 0000000000000..6f19300d19680 --- /dev/null +++ b/tests/baselines/reference/tsxReactEmitJsxFactory6.errors.txt @@ -0,0 +1,7 @@ +error TS5053: Option 'jsxFactory' cannot be specified with option 'reactNamespace'. + + +!!! error TS5053: Option 'jsxFactory' cannot be specified with option 'reactNamespace'. +==== tests/cases/conformance/jsx/file.tsx (0 errors) ==== + // An error should be issued when jsxFactory and reactNamespace are both specified. + \ No newline at end of file diff --git a/tests/baselines/reference/tsxReactEmitJsxFactory6.js b/tests/baselines/reference/tsxReactEmitJsxFactory6.js new file mode 100644 index 0000000000000..652ee8d0d3a11 --- /dev/null +++ b/tests/baselines/reference/tsxReactEmitJsxFactory6.js @@ -0,0 +1,6 @@ +//// [file.tsx] +// An error should be issued when jsxFactory and reactNamespace are both specified. + + +//// [file.js] +// An error should be issued when jsxFactory and reactNamespace are both specified. diff --git a/tests/baselines/reference/tsxReactEmitJsxFactory7.errors.txt b/tests/baselines/reference/tsxReactEmitJsxFactory7.errors.txt new file mode 100644 index 0000000000000..fad204d890fc9 --- /dev/null +++ b/tests/baselines/reference/tsxReactEmitJsxFactory7.errors.txt @@ -0,0 +1,7 @@ +error TS5067: Option 'jsxFactory' can only be used when 'jsx' is 'react'. + + +!!! error TS5067: Option 'jsxFactory' can only be used when 'jsx' is 'react'. +==== tests/cases/conformance/jsx/file.tsx (0 errors) ==== + // An error should be issued when 'jsxFactory' is used when 'jsx' is not 'react'. + \ No newline at end of file diff --git a/tests/baselines/reference/tsxReactEmitJsxFactory7.js b/tests/baselines/reference/tsxReactEmitJsxFactory7.js new file mode 100644 index 0000000000000..8bc875ecb0481 --- /dev/null +++ b/tests/baselines/reference/tsxReactEmitJsxFactory7.js @@ -0,0 +1,6 @@ +//// [file.tsx] +// An error should be issued when 'jsxFactory' is used when 'jsx' is not 'react'. + + +//// [file.jsx] +// An error should be issued when 'jsxFactory' is used when 'jsx' is not 'react'. diff --git a/tests/baselines/reference/tsxReactEmitJsxFactory8.errors.txt b/tests/baselines/reference/tsxReactEmitJsxFactory8.errors.txt new file mode 100644 index 0000000000000..e0b29e4aead43 --- /dev/null +++ b/tests/baselines/reference/tsxReactEmitJsxFactory8.errors.txt @@ -0,0 +1,7 @@ +error TS5068: Invalid value for 'jsxFactory'. '0' is not a valid identifier/qualified-name. + + +!!! error TS5068: Invalid value for 'jsxFactory'. '0' is not a valid identifier/qualified-name. +==== tests/cases/conformance/jsx/file.tsx (0 errors) ==== + // An error should be issued when 'jsxFactory' is an invalid identifier. + \ No newline at end of file diff --git a/tests/baselines/reference/tsxReactEmitJsxFactory8.js b/tests/baselines/reference/tsxReactEmitJsxFactory8.js new file mode 100644 index 0000000000000..75fd287adc337 --- /dev/null +++ b/tests/baselines/reference/tsxReactEmitJsxFactory8.js @@ -0,0 +1,6 @@ +//// [file.tsx] +// An error should be issued when 'jsxFactory' is an invalid identifier. + + +//// [file.js] +// An error should be issued when 'jsxFactory' is an invalid identifier. diff --git a/tests/baselines/reference/tsxReactEmitJsxFactory9.errors.txt b/tests/baselines/reference/tsxReactEmitJsxFactory9.errors.txt new file mode 100644 index 0000000000000..ae58ed3c8c9e1 --- /dev/null +++ b/tests/baselines/reference/tsxReactEmitJsxFactory9.errors.txt @@ -0,0 +1,7 @@ +error TS5068: Invalid value for 'jsxFactory'. 'h.0' is not a valid identifier/qualified-name. + + +!!! error TS5068: Invalid value for 'jsxFactory'. 'h.0' is not a valid identifier/qualified-name. +==== tests/cases/conformance/jsx/file.tsx (0 errors) ==== + // An error should be issued when 'jsxFactory' is an invalid qualified name. + \ No newline at end of file diff --git a/tests/baselines/reference/tsxReactEmitJsxFactory9.js b/tests/baselines/reference/tsxReactEmitJsxFactory9.js new file mode 100644 index 0000000000000..cdc5eeee444cc --- /dev/null +++ b/tests/baselines/reference/tsxReactEmitJsxFactory9.js @@ -0,0 +1,6 @@ +//// [file.tsx] +// An error should be issued when 'jsxFactory' is an invalid qualified name. + + +//// [file.js] +// An error should be issued when 'jsxFactory' is an invalid qualified name. diff --git a/tests/cases/conformance/jsx/tsxReactEmitJsxFactory1.tsx b/tests/cases/conformance/jsx/tsxReactEmitJsxFactory1.tsx new file mode 100644 index 0000000000000..6b89481604d1e --- /dev/null +++ b/tests/cases/conformance/jsx/tsxReactEmitJsxFactory1.tsx @@ -0,0 +1,11 @@ +//@filename: file.tsx +//@jsx: react +//@jsxFactory: h +declare module JSX { + interface IntrinsicElements { + [s: string]: any; + } +} + +// This should issue an error as 'h' is not declared. +
; diff --git a/tests/cases/conformance/jsx/tsxReactEmitJsxFactory2.tsx b/tests/cases/conformance/jsx/tsxReactEmitJsxFactory2.tsx new file mode 100644 index 0000000000000..31ba0bef2c557 --- /dev/null +++ b/tests/cases/conformance/jsx/tsxReactEmitJsxFactory2.tsx @@ -0,0 +1,12 @@ +//@filename: file.tsx +//@jsx: react +//@jsxFactory: h +declare module JSX { + interface IntrinsicElements { + [s: string]: any; + } +} + +declare var h: any; + +
; diff --git a/tests/cases/conformance/jsx/tsxReactEmitJsxFactory3.tsx b/tests/cases/conformance/jsx/tsxReactEmitJsxFactory3.tsx new file mode 100644 index 0000000000000..f34ab398bedc4 --- /dev/null +++ b/tests/cases/conformance/jsx/tsxReactEmitJsxFactory3.tsx @@ -0,0 +1,12 @@ +//@filename: file.tsx +//@jsx: react +//@jsxFactory: React.createElement +declare module JSX { + interface IntrinsicElements { + [s: string]: any; + } +} + +declare var React: any; + +
; diff --git a/tests/cases/conformance/jsx/tsxReactEmitJsxFactory4.tsx b/tests/cases/conformance/jsx/tsxReactEmitJsxFactory4.tsx new file mode 100644 index 0000000000000..912bf18984133 --- /dev/null +++ b/tests/cases/conformance/jsx/tsxReactEmitJsxFactory4.tsx @@ -0,0 +1,12 @@ +//@filename: file.tsx +//@jsx: react +//@jsxFactory: a.b.c +declare module JSX { + interface IntrinsicElements { + [s: string]: any; + } +} + +declare var a: any; + +
; diff --git a/tests/cases/conformance/jsx/tsxReactEmitJsxFactory5.tsx b/tests/cases/conformance/jsx/tsxReactEmitJsxFactory5.tsx new file mode 100644 index 0000000000000..bb0b73a8f956d --- /dev/null +++ b/tests/cases/conformance/jsx/tsxReactEmitJsxFactory5.tsx @@ -0,0 +1,16 @@ +//@filename: file.tsx +//@jsx: react +//@jsxFactory: h +declare module JSX { + interface IntrinsicElements { + [s: string]: any; + } +} + +//@filename: h.d.ts +export var h; + +//@filename: react-consumer.tsx +import {h} from "./h"; +// Should not elide h import +
; diff --git a/tests/cases/conformance/jsx/tsxReactEmitJsxFactory6.tsx b/tests/cases/conformance/jsx/tsxReactEmitJsxFactory6.tsx new file mode 100644 index 0000000000000..fa7d4c28a4a74 --- /dev/null +++ b/tests/cases/conformance/jsx/tsxReactEmitJsxFactory6.tsx @@ -0,0 +1,5 @@ +//@filename: file.tsx +//@jsx: react +// An error should be issued when jsxFactory and reactNamespace are both specified. +//@jsxFactory: React.createElement +//@reactNamespace: React diff --git a/tests/cases/conformance/jsx/tsxReactEmitJsxFactory7.tsx b/tests/cases/conformance/jsx/tsxReactEmitJsxFactory7.tsx new file mode 100644 index 0000000000000..54092e36857a3 --- /dev/null +++ b/tests/cases/conformance/jsx/tsxReactEmitJsxFactory7.tsx @@ -0,0 +1,4 @@ +//@filename: file.tsx +// An error should be issued when 'jsxFactory' is used when 'jsx' is not 'react'. +//@jsx: preserve +//@jsxFactory: h diff --git a/tests/cases/conformance/jsx/tsxReactEmitJsxFactory8.tsx b/tests/cases/conformance/jsx/tsxReactEmitJsxFactory8.tsx new file mode 100644 index 0000000000000..2227a6e29859e --- /dev/null +++ b/tests/cases/conformance/jsx/tsxReactEmitJsxFactory8.tsx @@ -0,0 +1,4 @@ +//@filename: file.tsx +//@jsx: react +// An error should be issued when 'jsxFactory' is an invalid identifier. +//@jsxFactory: 0 diff --git a/tests/cases/conformance/jsx/tsxReactEmitJsxFactory9.tsx b/tests/cases/conformance/jsx/tsxReactEmitJsxFactory9.tsx new file mode 100644 index 0000000000000..c928a1d42d891 --- /dev/null +++ b/tests/cases/conformance/jsx/tsxReactEmitJsxFactory9.tsx @@ -0,0 +1,4 @@ +//@filename: file.tsx +//@jsx: react +// An error should be issued when 'jsxFactory' is an invalid qualified name. +//@jsxFactory: h.0