@@ -954,16 +954,32 @@ namespace ts {
954
954
if (location) {
955
955
const file = getSourceFileOfNode(location);
956
956
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
+ }
959
970
}
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
+ }
967
983
}
968
984
}
969
985
}
@@ -23736,10 +23752,14 @@ namespace ts {
23736
23752
function checkJsxFragment(node: JsxFragment): Type {
23737
23753
checkJsxOpeningLikeElementOrOpeningFragment(node.openingFragment);
23738
23754
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")) {
23740
23760
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 );
23743
23763
}
23744
23764
23745
23765
checkJsxChildren(node);
@@ -24197,21 +24217,28 @@ namespace ts {
24197
24217
if (isNodeOpeningLikeElement) {
24198
24218
checkGrammarJsxElement(<JsxOpeningLikeElement>node);
24199
24219
}
24220
+
24200
24221
checkJsxPreconditions(node);
24201
24222
// The reactNamespace/jsxFactory's root symbol should be marked as 'used' so we don't incorrectly elide its import.
24202
24223
// 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) {
24208
24235
// 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;
24211
24238
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 );
24215
24242
}
24216
24243
}
24217
24244
@@ -36728,10 +36755,31 @@ namespace ts {
36728
36755
return literalTypeToNode(<FreshableType>type, node, tracker);
36729
36756
}
36730
36757
36731
- function getJsxFactoryEntity(location: Node) {
36758
+ function getJsxFactoryEntity(location: Node): EntityName | undefined {
36732
36759
return location ? (getJsxNamespace(location), (getSourceFileOfNode(location).localJsxFactory || _jsxFactoryEntity)) : _jsxFactoryEntity;
36733
36760
}
36734
36761
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
+
36735
36783
function createResolver(): EmitResolver {
36736
36784
// this variable and functions that use it are deliberately moved here from the outer scope
36737
36785
// to avoid scope pollution
@@ -36806,6 +36854,7 @@ namespace ts {
36806
36854
return !!(symbol && getCheckFlags(symbol) & CheckFlags.Late);
36807
36855
},
36808
36856
getJsxFactoryEntity,
36857
+ getJsxFragmentFactoryEntity,
36809
36858
getAllAccessorDeclarations(accessor: AccessorDeclaration): AllAccessorDeclarations {
36810
36859
accessor = getParseTreeNode(accessor, isGetOrSetAccessorDeclaration)!; // TODO: GH#18217
36811
36860
const otherKind = accessor.kind === SyntaxKind.SetAccessor ? SyntaxKind.GetAccessor : SyntaxKind.SetAccessor;
0 commit comments