mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
reset soft with master for single commit (#38720)
This commit is contained in:
+73
-24
@@ -954,16 +954,32 @@ namespace ts {
|
||||
if (location) {
|
||||
const file = getSourceFileOfNode(location);
|
||||
if (file) {
|
||||
if (file.localJsxNamespace) {
|
||||
return file.localJsxNamespace;
|
||||
if (isJsxOpeningFragment(location)) {
|
||||
if (file.localJsxFragmentNamespace) {
|
||||
return file.localJsxFragmentNamespace;
|
||||
}
|
||||
const jsxFragmentPragma = file.pragmas.get("jsxfrag");
|
||||
if (jsxFragmentPragma) {
|
||||
const chosenPragma = isArray(jsxFragmentPragma) ? jsxFragmentPragma[0] : jsxFragmentPragma;
|
||||
file.localJsxFragmentFactory = parseIsolatedEntityName(chosenPragma.arguments.factory, languageVersion);
|
||||
visitNode(file.localJsxFragmentFactory, markAsSynthetic);
|
||||
if (file.localJsxFragmentFactory) {
|
||||
return file.localJsxFragmentNamespace = getFirstIdentifier(file.localJsxFragmentFactory).escapedText;
|
||||
}
|
||||
}
|
||||
}
|
||||
const jsxPragma = file.pragmas.get("jsx");
|
||||
if (jsxPragma) {
|
||||
const chosenpragma = isArray(jsxPragma) ? jsxPragma[0] : jsxPragma;
|
||||
file.localJsxFactory = parseIsolatedEntityName(chosenpragma.arguments.factory, languageVersion);
|
||||
visitNode(file.localJsxFactory, markAsSynthetic);
|
||||
if (file.localJsxFactory) {
|
||||
return file.localJsxNamespace = getFirstIdentifier(file.localJsxFactory).escapedText;
|
||||
else {
|
||||
if (file.localJsxNamespace) {
|
||||
return file.localJsxNamespace;
|
||||
}
|
||||
const jsxPragma = file.pragmas.get("jsx");
|
||||
if (jsxPragma) {
|
||||
const chosenPragma = isArray(jsxPragma) ? jsxPragma[0] : jsxPragma;
|
||||
file.localJsxFactory = parseIsolatedEntityName(chosenPragma.arguments.factory, languageVersion);
|
||||
visitNode(file.localJsxFactory, markAsSynthetic);
|
||||
if (file.localJsxFactory) {
|
||||
return file.localJsxNamespace = getFirstIdentifier(file.localJsxFactory).escapedText;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23736,10 +23752,14 @@ namespace ts {
|
||||
function checkJsxFragment(node: JsxFragment): Type {
|
||||
checkJsxOpeningLikeElementOrOpeningFragment(node.openingFragment);
|
||||
|
||||
if (compilerOptions.jsx === JsxEmit.React && (compilerOptions.jsxFactory || getSourceFileOfNode(node).pragmas.has("jsx"))) {
|
||||
// by default, jsx:'react' will use jsxFactory = React.createElement and jsxFragmentFactory = React.Fragment
|
||||
// if jsxFactory compiler option is provided, ensure jsxFragmentFactory compiler option or @jsxFrag pragma is provided too
|
||||
const nodeSourceFile = getSourceFileOfNode(node);
|
||||
if (compilerOptions.jsx === JsxEmit.React && (compilerOptions.jsxFactory || nodeSourceFile.pragmas.has("jsx"))
|
||||
&& !compilerOptions.jsxFragmentFactory && !nodeSourceFile.pragmas.has("jsxfrag")) {
|
||||
error(node, compilerOptions.jsxFactory
|
||||
? Diagnostics.JSX_fragment_is_not_supported_when_using_jsxFactory
|
||||
: Diagnostics.JSX_fragment_is_not_supported_when_using_an_inline_JSX_factory_pragma);
|
||||
? Diagnostics.The_jsxFragmentFactory_compiler_option_must_be_provided_to_use_JSX_fragments_with_the_jsxFactory_compiler_option
|
||||
: Diagnostics.An_jsxFrag_pragma_is_required_when_using_an_jsx_pragma_with_JSX_fragments);
|
||||
}
|
||||
|
||||
checkJsxChildren(node);
|
||||
@@ -24197,21 +24217,28 @@ namespace ts {
|
||||
if (isNodeOpeningLikeElement) {
|
||||
checkGrammarJsxElement(<JsxOpeningLikeElement>node);
|
||||
}
|
||||
|
||||
checkJsxPreconditions(node);
|
||||
// The reactNamespace/jsxFactory's root symbol should be marked as 'used' so we don't incorrectly elide its import.
|
||||
// And if there is no reactNamespace/jsxFactory's symbol in scope when targeting React emit, we should issue an error.
|
||||
const reactRefErr = diagnostics && compilerOptions.jsx === JsxEmit.React ? Diagnostics.Cannot_find_name_0 : undefined;
|
||||
const reactNamespace = getJsxNamespace(node);
|
||||
const reactLocation = isNodeOpeningLikeElement ? (<JsxOpeningLikeElement>node).tagName : node;
|
||||
const reactSym = resolveName(reactLocation, reactNamespace, SymbolFlags.Value, reactRefErr, reactNamespace, /*isUse*/ true);
|
||||
if (reactSym) {
|
||||
// Mark local symbol as referenced here because it might not have been marked
|
||||
// if jsx emit was not react as there wont be error being emitted
|
||||
reactSym.isReferenced = SymbolFlags.All;
|
||||
const jsxFactoryRefErr = diagnostics && compilerOptions.jsx === JsxEmit.React ? Diagnostics.Cannot_find_name_0 : undefined;
|
||||
const jsxFactoryNamespace = getJsxNamespace(node);
|
||||
const jsxFactoryLocation = isNodeOpeningLikeElement ? (<JsxOpeningLikeElement>node).tagName : node;
|
||||
|
||||
// If react symbol is alias, mark it as referenced
|
||||
if (reactSym.flags & SymbolFlags.Alias && !getTypeOnlyAliasDeclaration(reactSym)) {
|
||||
markAliasSymbolAsReferenced(reactSym);
|
||||
// allow null as jsxFragmentFactory
|
||||
let jsxFactorySym: Symbol | undefined;
|
||||
if (!(isJsxOpeningFragment(node) && jsxFactoryNamespace === "null")) {
|
||||
jsxFactorySym = resolveName(jsxFactoryLocation, jsxFactoryNamespace, SymbolFlags.Value, jsxFactoryRefErr, jsxFactoryNamespace, /*isUse*/ true);
|
||||
}
|
||||
|
||||
if (jsxFactorySym) {
|
||||
// Mark local symbol as referenced here because it might not have been marked
|
||||
// if jsx emit was not jsxFactory as there wont be error being emitted
|
||||
jsxFactorySym.isReferenced = SymbolFlags.All;
|
||||
|
||||
// If react/jsxFactory symbol is alias, mark it as refereced
|
||||
if (jsxFactorySym.flags & SymbolFlags.Alias && !getTypeOnlyAliasDeclaration(jsxFactorySym)) {
|
||||
markAliasSymbolAsReferenced(jsxFactorySym);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36728,10 +36755,31 @@ namespace ts {
|
||||
return literalTypeToNode(<FreshableType>type, node, tracker);
|
||||
}
|
||||
|
||||
function getJsxFactoryEntity(location: Node) {
|
||||
function getJsxFactoryEntity(location: Node): EntityName | undefined {
|
||||
return location ? (getJsxNamespace(location), (getSourceFileOfNode(location).localJsxFactory || _jsxFactoryEntity)) : _jsxFactoryEntity;
|
||||
}
|
||||
|
||||
function getJsxFragmentFactoryEntity(location: Node): EntityName | undefined {
|
||||
if (location) {
|
||||
const file = getSourceFileOfNode(location);
|
||||
if (file) {
|
||||
if (file.localJsxFragmentFactory) {
|
||||
return file.localJsxFragmentFactory;
|
||||
}
|
||||
const jsxFragPragmas = file.pragmas.get("jsxfrag");
|
||||
const jsxFragPragma = isArray(jsxFragPragmas) ? jsxFragPragmas[0] : jsxFragPragmas;
|
||||
if (jsxFragPragma) {
|
||||
file.localJsxFragmentFactory = parseIsolatedEntityName(jsxFragPragma.arguments.factory, languageVersion);
|
||||
return file.localJsxFragmentFactory;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (compilerOptions.jsxFragmentFactory) {
|
||||
return parseIsolatedEntityName(compilerOptions.jsxFragmentFactory, languageVersion);
|
||||
}
|
||||
}
|
||||
|
||||
function createResolver(): EmitResolver {
|
||||
// this variable and functions that use it are deliberately moved here from the outer scope
|
||||
// to avoid scope pollution
|
||||
@@ -36806,6 +36854,7 @@ namespace ts {
|
||||
return !!(symbol && getCheckFlags(symbol) & CheckFlags.Late);
|
||||
},
|
||||
getJsxFactoryEntity,
|
||||
getJsxFragmentFactoryEntity,
|
||||
getAllAccessorDeclarations(accessor: AccessorDeclaration): AllAccessorDeclarations {
|
||||
accessor = getParseTreeNode(accessor, isGetOrSetAccessorDeclaration)!; // TODO: GH#18217
|
||||
const otherKind = accessor.kind === SyntaxKind.SetAccessor ? SyntaxKind.GetAccessor : SyntaxKind.SetAccessor;
|
||||
|
||||
@@ -766,6 +766,12 @@ namespace ts {
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.Specify_the_JSX_factory_function_to_use_when_targeting_react_JSX_emit_e_g_React_createElement_or_h
|
||||
},
|
||||
{
|
||||
name: "jsxFragmentFactory",
|
||||
type: "string",
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.Specify_the_JSX_fragment_factory_function_to_use_when_targeting_react_JSX_emit_with_jsxFactory_compiler_option_is_specified_e_g_Fragment
|
||||
},
|
||||
{
|
||||
name: "resolveJsonModule",
|
||||
type: "boolean",
|
||||
|
||||
@@ -5027,11 +5027,11 @@
|
||||
"category": "Error",
|
||||
"code": 17015
|
||||
},
|
||||
"JSX fragment is not supported when using --jsxFactory": {
|
||||
"The 'jsxFragmentFactory' compiler option must be provided to use JSX fragments with the 'jsxFactory' compiler option.": {
|
||||
"category": "Error",
|
||||
"code": 17016
|
||||
},
|
||||
"JSX fragment is not supported when using an inline JSX factory pragma": {
|
||||
"An @jsxFrag pragma is required when using an @jsx pragma with JSX fragments.": {
|
||||
"category": "Error",
|
||||
"code": 17017
|
||||
},
|
||||
@@ -5837,5 +5837,13 @@
|
||||
"Only numeric enums can have computed members, but this expression has type '{0}'. If you do not need exhaustiveness checks, consider using an object literal instead.": {
|
||||
"category": "Error",
|
||||
"code": 18033
|
||||
},
|
||||
"Specify the JSX fragment factory function to use when targeting 'react' JSX emit with 'jsxFactory' compiler option is specified, e.g. 'Fragment'.": {
|
||||
"category": "Message",
|
||||
"code": 18034
|
||||
},
|
||||
"Invalid value for 'jsxFragmentFactory'. '{0}' is not a valid identifier or qualified-name.": {
|
||||
"category": "Error",
|
||||
"code": 18035
|
||||
}
|
||||
}
|
||||
|
||||
@@ -660,6 +660,7 @@ namespace ts {
|
||||
getTypeReferenceDirectivesForSymbol: notImplemented,
|
||||
isLiteralConstDeclaration: notImplemented,
|
||||
getJsxFactoryEntity: notImplemented,
|
||||
getJsxFragmentFactoryEntity: notImplemented,
|
||||
getAllAccessorDeclarations: notImplemented,
|
||||
getSymbolOfExternalModuleSpecifier: notImplemented,
|
||||
isBindingCapturedByNode: notImplemented,
|
||||
|
||||
@@ -55,6 +55,15 @@ namespace ts {
|
||||
);
|
||||
}
|
||||
|
||||
function createJsxFragmentFactoryExpression(factory: NodeFactory, jsxFragmentFactoryEntity: EntityName | undefined, reactNamespace: string, parent: JsxOpeningLikeElement | JsxOpeningFragment): Expression {
|
||||
return jsxFragmentFactoryEntity ?
|
||||
createJsxFactoryExpressionFromEntityName(factory, jsxFragmentFactoryEntity, parent) :
|
||||
factory.createPropertyAccessExpression(
|
||||
createReactNamespace(reactNamespace, parent),
|
||||
"Fragment"
|
||||
);
|
||||
}
|
||||
|
||||
export function createExpressionForJsxElement(factory: NodeFactory, jsxFactoryEntity: EntityName | undefined, reactNamespace: string, tagName: Expression, props: Expression | undefined, children: readonly Expression[] | undefined, parentElement: JsxOpeningLikeElement, location: TextRange): LeftHandSideExpression {
|
||||
const argumentsList = [tagName];
|
||||
if (props) {
|
||||
@@ -87,14 +96,9 @@ namespace ts {
|
||||
);
|
||||
}
|
||||
|
||||
export function createExpressionForJsxFragment(factory: NodeFactory, jsxFactoryEntity: EntityName | undefined, reactNamespace: string, children: readonly Expression[], parentElement: JsxOpeningFragment, location: TextRange): LeftHandSideExpression {
|
||||
const tagName = factory.createPropertyAccessExpression(
|
||||
createReactNamespace(reactNamespace, parentElement),
|
||||
"Fragment"
|
||||
);
|
||||
|
||||
const argumentsList = [<Expression>tagName];
|
||||
argumentsList.push(factory.createNull());
|
||||
export function createExpressionForJsxFragment(factory: NodeFactory, jsxFactoryEntity: EntityName | undefined, jsxFragmentFactoryEntity: EntityName | undefined, reactNamespace: string, children: readonly Expression[], parentElement: JsxOpeningFragment, location: TextRange): LeftHandSideExpression {
|
||||
const tagName = createJsxFragmentFactoryExpression(factory, jsxFragmentFactoryEntity, reactNamespace, parentElement);
|
||||
const argumentsList = [tagName, factory.createNull()];
|
||||
|
||||
if (children && children.length > 0) {
|
||||
if (children.length > 1) {
|
||||
@@ -820,4 +824,4 @@ namespace ts {
|
||||
export function isStaticModifier(node: Modifier): node is StaticKeyword {
|
||||
return node.kind === SyntaxKind.StaticKeyword;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8568,7 +8568,9 @@ namespace ts {
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "jsx": return; // Accessed directly
|
||||
case "jsx":
|
||||
case "jsxfrag":
|
||||
return; // Accessed directly
|
||||
default: Debug.fail("Unhandled pragma kind"); // Can this be made into an assertNever in the future?
|
||||
}
|
||||
});
|
||||
|
||||
@@ -3196,6 +3196,15 @@ namespace ts {
|
||||
createOptionValueDiagnostic("reactNamespace", Diagnostics.Invalid_value_for_reactNamespace_0_is_not_a_valid_identifier, options.reactNamespace);
|
||||
}
|
||||
|
||||
if (options.jsxFragmentFactory) {
|
||||
if (!options.jsxFactory) {
|
||||
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "jsxFragmentFactory", "jsxFactory");
|
||||
}
|
||||
if (!parseIsolatedEntityName(options.jsxFragmentFactory, languageVersion)) {
|
||||
createOptionValueDiagnostic("jsxFragmentFactory", Diagnostics.Invalid_value_for_jsxFragmentFactory_0_is_not_a_valid_identifier_or_qualified_name, options.jsxFragmentFactory);
|
||||
}
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
||||
@@ -142,6 +142,7 @@ namespace ts {
|
||||
const element = createExpressionForJsxFragment(
|
||||
factory,
|
||||
context.getEmitResolver().getJsxFactoryEntity(currentSourceFile),
|
||||
context.getEmitResolver().getJsxFragmentFactoryEntity(currentSourceFile),
|
||||
compilerOptions.reactNamespace!, // TODO: GH#18217
|
||||
mapDefined(children, transformJsxChildToExpression),
|
||||
node,
|
||||
|
||||
@@ -3454,7 +3454,9 @@ namespace ts {
|
||||
/* @internal */ version: string;
|
||||
/* @internal */ pragmas: ReadonlyPragmaMap;
|
||||
/* @internal */ localJsxNamespace?: __String;
|
||||
/* @internal */ localJsxFragmentNamespace?: __String;
|
||||
/* @internal */ localJsxFactory?: EntityName;
|
||||
/* @internal */ localJsxFragmentFactory?: EntityName;
|
||||
|
||||
/* @internal */ exportedModulesFromDeclarationEmit?: ExportedModulesFromDeclarationEmit;
|
||||
}
|
||||
@@ -4463,6 +4465,7 @@ namespace ts {
|
||||
getTypeReferenceDirectivesForSymbol(symbol: Symbol, meaning?: SymbolFlags): string[] | undefined;
|
||||
isLiteralConstDeclaration(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration): boolean;
|
||||
getJsxFactoryEntity(location?: Node): EntityName | undefined;
|
||||
getJsxFragmentFactoryEntity(location?: Node): EntityName | undefined;
|
||||
getAllAccessorDeclarations(declaration: AccessorDeclaration): AllAccessorDeclarations;
|
||||
getSymbolOfExternalModuleSpecifier(node: StringLiteralLike): Symbol | undefined;
|
||||
isBindingCapturedByNode(node: Node, decl: VariableDeclaration | BindingElement): boolean;
|
||||
@@ -5681,6 +5684,7 @@ namespace ts {
|
||||
/* @internal */ pretty?: boolean;
|
||||
reactNamespace?: string;
|
||||
jsxFactory?: string;
|
||||
jsxFragmentFactory?: string;
|
||||
composite?: boolean;
|
||||
incremental?: boolean;
|
||||
tsBuildInfoFile?: string;
|
||||
@@ -7928,6 +7932,10 @@ namespace ts {
|
||||
args: [{ name: "factory" }],
|
||||
kind: PragmaKindFlags.MultiLine
|
||||
},
|
||||
"jsxfrag": {
|
||||
args: [{ name: "factory" }],
|
||||
kind: PragmaKindFlags.MultiLine
|
||||
},
|
||||
} as const;
|
||||
|
||||
/* @internal */
|
||||
|
||||
@@ -363,6 +363,10 @@ var x = 0;`, {
|
||||
options: { compilerOptions: { jsxFactory: "createElement" }, fileName: "input.js", reportDiagnostics: true }
|
||||
});
|
||||
|
||||
transpilesCorrectly("Supports setting 'jsxFragmentFactory'", "x;", {
|
||||
options: { compilerOptions: { jsxFactory: "x", jsxFragmentFactory: "frag" }, fileName: "input.js", reportDiagnostics: true }
|
||||
});
|
||||
|
||||
transpilesCorrectly("Supports setting 'removeComments'", "x;", {
|
||||
options: { compilerOptions: { removeComments: true }, fileName: "input.js", reportDiagnostics: true }
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user