diff --git a/lib/tsserverlibrary.d.ts b/lib/tsserverlibrary.d.ts
index 63580ce8dcd7f..4e51438f41145 100644
--- a/lib/tsserverlibrary.d.ts
+++ b/lib/tsserverlibrary.d.ts
@@ -1,18 +1,18 @@
-/*! *****************************************************************************
-Copyright (c) Microsoft Corporation. All rights reserved.
-Licensed under the Apache License, Version 2.0 (the "License"); you may not use
-this file except in compliance with the License. You may obtain a copy of the
-License at http://www.apache.org/licenses/LICENSE-2.0
-
-THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
-WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
-MERCHANTABLITY OR NON-INFRINGEMENT.
-
-See the Apache Version 2.0 License for specific language governing permissions
-and limitations under the License.
-***************************************************************************** */
-
+/*! *****************************************************************************
+Copyright (c) Microsoft Corporation. All rights reserved.
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use
+this file except in compliance with the License. You may obtain a copy of the
+License at http://www.apache.org/licenses/LICENSE-2.0
+
+THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
+WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
+MERCHANTABLITY OR NON-INFRINGEMENT.
+
+See the Apache Version 2.0 License for specific language governing permissions
+and limitations under the License.
+***************************************************************************** */
+
///
///
declare namespace ts {
@@ -3509,6 +3509,7 @@ declare namespace ts.server.protocol {
type None = "None";
type Preserve = "Preserve";
type React = "React";
+ type Local = "Local";
}
type JsxEmit = JsxEmit.None | JsxEmit.Preserve | JsxEmit.React;
namespace ModuleKind {
diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 0f2c642124afc..24fd7550ecfcd 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -11346,6 +11346,23 @@ namespace ts {
}
}
+ // if JSX mode is local, check that createElement is in scope
+ if (compilerOptions.jsx === JsxEmit.Local) {
+ const createElementRefError = Diagnostics.Cannot_find_name_0;
+ const createElementFnName = "createElement";
+ const createElementSym = resolveName(node.tagName, createElementFnName, SymbolFlags.Value, createElementRefError, createElementFnName);
+ if (createElementSym) {
+ // Mark local symbol as referenced here because it might not have been marked
+ // if jsx emit was not simple as there wont be error being emitted
+ createElementSym.isReferenced = true;
+
+ // If createElement symbol is alias, mark it as refereced
+ if (createElementSym.flags & SymbolFlags.Alias && !isConstEnumOrConstEnumOnlyModule(resolveAlias(createElementSym))) {
+ markAliasSymbolAsReferenced(createElementSym);
+ }
+ }
+ }
+
const targetAttributesType = getJsxElementAttributesType(node);
const nameTable = createMap();
diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts
index 50399fd5c38e7..63d2c47349faa 100644
--- a/src/compiler/commandLineParser.ts
+++ b/src/compiler/commandLineParser.ts
@@ -67,7 +67,8 @@ namespace ts {
name: "jsx",
type: createMap({
"preserve": JsxEmit.Preserve,
- "react": JsxEmit.React
+ "react": JsxEmit.React,
+ "local": JsxEmit.Local
}),
paramType: Diagnostics.KIND,
description: Diagnostics.Specify_JSX_code_generation_Colon_preserve_or_react,
diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts
index c557e3514a5de..759cad69c9e21 100644
--- a/src/compiler/factory.ts
+++ b/src/compiler/factory.ts
@@ -1628,7 +1628,19 @@ namespace ts {
return react;
}
- export function createReactCreateElement(reactNamespace: string, tagName: Expression, props: Expression, children: Expression[], parentElement: JsxOpeningLikeElement, location: TextRange): LeftHandSideExpression {
+ function createSynthCreateElement(parent: 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("createElement");
+ react.flags &= ~NodeFlags.Synthesized;
+ // Set the parent that is in parse tree
+ // this makes sure that parent chain is intact for checker to traverse complete scope tree
+ react.parent = getParseTreeNode(parent);
+ return react;
+ }
+
+ export function createReactCreateElement(reactNamespace: string, tagName: Expression, props: Expression, children: Expression[], parentElement: JsxOpeningLikeElement, location: TextRange, jsxEmit: JsxEmit): LeftHandSideExpression {
const argumentsList = [tagName];
if (props) {
argumentsList.push(props);
@@ -1650,12 +1662,20 @@ namespace ts {
}
}
+ if (jsxEmit === JsxEmit.Local) {
+ return createCall(
+ createSynthCreateElement(parentElement),
+ /*typeArguments*/ undefined,
+ argumentsList,
+ location);
+ }
+
return createCall(
createPropertyAccess(
createReactNamespace(reactNamespace, parentElement),
"createElement"
),
- /*typeArguments*/ undefined,
+ /*typeArguments*/ undefined,
argumentsList,
location
);
diff --git a/src/compiler/transformer.ts b/src/compiler/transformer.ts
index ee9c081e6ebd8..0809affebff67 100644
--- a/src/compiler/transformer.ts
+++ b/src/compiler/transformer.ts
@@ -112,7 +112,7 @@ namespace ts {
transformers.push(transformTypeScript);
- if (jsx === JsxEmit.React) {
+ if (jsx === JsxEmit.React || jsx === JsxEmit.Local) {
transformers.push(transformJsx);
}
diff --git a/src/compiler/transformers/jsx.ts b/src/compiler/transformers/jsx.ts
index 95a4016bb0aeb..2cc7af2524589 100644
--- a/src/compiler/transformers/jsx.ts
+++ b/src/compiler/transformers/jsx.ts
@@ -112,14 +112,15 @@ namespace ts {
objectProperties = singleOrUndefined(segments)
|| createAssignHelper(currentSourceFile.externalHelpersModuleName, segments);
}
-
+
const element = createReactCreateElement(
compilerOptions.reactNamespace,
tagName,
objectProperties,
filter(map(children, transformJsxChildToExpression), isDefined),
node,
- location
+ location,
+ compilerOptions.jsx
);
if (isChild) {
diff --git a/src/compiler/types.ts b/src/compiler/types.ts
index 5536a818df536..00d06675eb238 100644
--- a/src/compiler/types.ts
+++ b/src/compiler/types.ts
@@ -3131,7 +3131,8 @@ namespace ts {
export const enum JsxEmit {
None = 0,
Preserve = 1,
- React = 2
+ React = 2,
+ Local = 3
}
export const enum NewLineKind {