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 {