@@ -954,16 +954,32 @@ namespace ts {
954954 if (location) {
955955 const file = getSourceFileOfNode(location);
956956 if (file) {
957- if (file.localJsxNamespace) {
958- return file.localJsxNamespace;
957+ if (isJsxOpeningFragment(location)) {
958+ if (file.localJsxFragmentNamespace) {
959+ return file.localJsxFragmentNamespace;
960+ }
961+ const jsxFragmentPragma = file.pragmas.get("jsxfrag");
962+ if (jsxFragmentPragma) {
963+ const chosenPragma = isArray(jsxFragmentPragma) ? jsxFragmentPragma[0] : jsxFragmentPragma;
964+ file.localJsxFragmentFactory = parseIsolatedEntityName(chosenPragma.arguments.factory, languageVersion);
965+ visitNode(file.localJsxFragmentFactory, markAsSynthetic);
966+ if (file.localJsxFragmentFactory) {
967+ return file.localJsxFragmentNamespace = getFirstIdentifier(file.localJsxFragmentFactory).escapedText;
968+ }
969+ }
959970 }
960- const jsxPragma = file.pragmas.get("jsx");
961- if (jsxPragma) {
962- const chosenpragma = isArray(jsxPragma) ? jsxPragma[0] : jsxPragma;
963- file.localJsxFactory = parseIsolatedEntityName(chosenpragma.arguments.factory, languageVersion);
964- visitNode(file.localJsxFactory, markAsSynthetic);
965- if (file.localJsxFactory) {
966- return file.localJsxNamespace = getFirstIdentifier(file.localJsxFactory).escapedText;
971+ else {
972+ if (file.localJsxNamespace) {
973+ return file.localJsxNamespace;
974+ }
975+ const jsxPragma = file.pragmas.get("jsx");
976+ if (jsxPragma) {
977+ const chosenPragma = isArray(jsxPragma) ? jsxPragma[0] : jsxPragma;
978+ file.localJsxFactory = parseIsolatedEntityName(chosenPragma.arguments.factory, languageVersion);
979+ visitNode(file.localJsxFactory, markAsSynthetic);
980+ if (file.localJsxFactory) {
981+ return file.localJsxNamespace = getFirstIdentifier(file.localJsxFactory).escapedText;
982+ }
967983 }
968984 }
969985 }
@@ -23736,10 +23752,14 @@ namespace ts {
2373623752 function checkJsxFragment(node: JsxFragment): Type {
2373723753 checkJsxOpeningLikeElementOrOpeningFragment(node.openingFragment);
2373823754
23739- if (compilerOptions.jsx === JsxEmit.React && (compilerOptions.jsxFactory || getSourceFileOfNode(node).pragmas.has("jsx"))) {
23755+ // by default, jsx:'react' will use jsxFactory = React.createElement and jsxFragmentFactory = React.Fragment
23756+ // if jsxFactory compiler option is provided, ensure jsxFragmentFactory compiler option or @jsxFrag pragma is provided too
23757+ const nodeSourceFile = getSourceFileOfNode(node);
23758+ if (compilerOptions.jsx === JsxEmit.React && (compilerOptions.jsxFactory || nodeSourceFile.pragmas.has("jsx"))
23759+ && !compilerOptions.jsxFragmentFactory && !nodeSourceFile.pragmas.has("jsxfrag")) {
2374023760 error(node, compilerOptions.jsxFactory
23741- ? Diagnostics.JSX_fragment_is_not_supported_when_using_jsxFactory
23742- : Diagnostics.JSX_fragment_is_not_supported_when_using_an_inline_JSX_factory_pragma );
23761+ ? Diagnostics.The_jsxFragmentFactory_compiler_option_must_be_provided_to_use_JSX_fragments_with_the_jsxFactory_compiler_option
23762+ : Diagnostics.An_jsxFrag_pragma_is_required_when_using_an_jsx_pragma_with_JSX_fragments );
2374323763 }
2374423764
2374523765 checkJsxChildren(node);
@@ -24197,21 +24217,28 @@ namespace ts {
2419724217 if (isNodeOpeningLikeElement) {
2419824218 checkGrammarJsxElement(<JsxOpeningLikeElement>node);
2419924219 }
24220+
2420024221 checkJsxPreconditions(node);
2420124222 // The reactNamespace/jsxFactory's root symbol should be marked as 'used' so we don't incorrectly elide its import.
2420224223 // And if there is no reactNamespace/jsxFactory's symbol in scope when targeting React emit, we should issue an error.
24203- const reactRefErr = diagnostics && compilerOptions.jsx === JsxEmit.React ? Diagnostics.Cannot_find_name_0 : undefined;
24204- const reactNamespace = getJsxNamespace(node);
24205- const reactLocation = isNodeOpeningLikeElement ? (<JsxOpeningLikeElement>node).tagName : node;
24206- const reactSym = resolveName(reactLocation, reactNamespace, SymbolFlags.Value, reactRefErr, reactNamespace, /*isUse*/ true);
24207- if (reactSym) {
24224+ const jsxFactoryRefErr = diagnostics && compilerOptions.jsx === JsxEmit.React ? Diagnostics.Cannot_find_name_0 : undefined;
24225+ const jsxFactoryNamespace = getJsxNamespace(node);
24226+ const jsxFactoryLocation = isNodeOpeningLikeElement ? (<JsxOpeningLikeElement>node).tagName : node;
24227+
24228+ // allow null as jsxFragmentFactory
24229+ let jsxFactorySym: Symbol | undefined;
24230+ if (!(isJsxOpeningFragment(node) && jsxFactoryNamespace === "null")) {
24231+ jsxFactorySym = resolveName(jsxFactoryLocation, jsxFactoryNamespace, SymbolFlags.Value, jsxFactoryRefErr, jsxFactoryNamespace, /*isUse*/ true);
24232+ }
24233+
24234+ if (jsxFactorySym) {
2420824235 // Mark local symbol as referenced here because it might not have been marked
24209- // if jsx emit was not react as there wont be error being emitted
24210- reactSym .isReferenced = SymbolFlags.All;
24236+ // if jsx emit was not jsxFactory as there wont be error being emitted
24237+ jsxFactorySym .isReferenced = SymbolFlags.All;
2421124238
24212- // If react symbol is alias, mark it as referenced
24213- if (reactSym .flags & SymbolFlags.Alias && !getTypeOnlyAliasDeclaration(reactSym )) {
24214- markAliasSymbolAsReferenced(reactSym );
24239+ // If react/jsxFactory symbol is alias, mark it as refereced
24240+ if (jsxFactorySym .flags & SymbolFlags.Alias && !getTypeOnlyAliasDeclaration(jsxFactorySym )) {
24241+ markAliasSymbolAsReferenced(jsxFactorySym );
2421524242 }
2421624243 }
2421724244
@@ -36728,10 +36755,31 @@ namespace ts {
3672836755 return literalTypeToNode(<FreshableType>type, node, tracker);
3672936756 }
3673036757
36731- function getJsxFactoryEntity(location: Node) {
36758+ function getJsxFactoryEntity(location: Node): EntityName | undefined {
3673236759 return location ? (getJsxNamespace(location), (getSourceFileOfNode(location).localJsxFactory || _jsxFactoryEntity)) : _jsxFactoryEntity;
3673336760 }
3673436761
36762+ function getJsxFragmentFactoryEntity(location: Node): EntityName | undefined {
36763+ if (location) {
36764+ const file = getSourceFileOfNode(location);
36765+ if (file) {
36766+ if (file.localJsxFragmentFactory) {
36767+ return file.localJsxFragmentFactory;
36768+ }
36769+ const jsxFragPragmas = file.pragmas.get("jsxfrag");
36770+ const jsxFragPragma = isArray(jsxFragPragmas) ? jsxFragPragmas[0] : jsxFragPragmas;
36771+ if (jsxFragPragma) {
36772+ file.localJsxFragmentFactory = parseIsolatedEntityName(jsxFragPragma.arguments.factory, languageVersion);
36773+ return file.localJsxFragmentFactory;
36774+ }
36775+ }
36776+ }
36777+
36778+ if (compilerOptions.jsxFragmentFactory) {
36779+ return parseIsolatedEntityName(compilerOptions.jsxFragmentFactory, languageVersion);
36780+ }
36781+ }
36782+
3673536783 function createResolver(): EmitResolver {
3673636784 // this variable and functions that use it are deliberately moved here from the outer scope
3673736785 // to avoid scope pollution
@@ -36806,6 +36854,7 @@ namespace ts {
3680636854 return !!(symbol && getCheckFlags(symbol) & CheckFlags.Late);
3680736855 },
3680836856 getJsxFactoryEntity,
36857+ getJsxFragmentFactoryEntity,
3680936858 getAllAccessorDeclarations(accessor: AccessorDeclaration): AllAccessorDeclarations {
3681036859 accessor = getParseTreeNode(accessor, isGetOrSetAccessorDeclaration)!; // TODO: GH#18217
3681136860 const otherKind = accessor.kind === SyntaxKind.SetAccessor ? SyntaxKind.GetAccessor : SyntaxKind.SetAccessor;
0 commit comments