Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add emit support for jsx/jsxs experimental jsx runtime api #39199

Merged
merged 2 commits into from Sep 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/compiler/checker.ts
Expand Up @@ -24535,7 +24535,7 @@ namespace ts {
// 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"))
if (getJSXTransformEnabled(compilerOptions) && (compilerOptions.jsxFactory || nodeSourceFile.pragmas.has("jsx"))
&& !compilerOptions.jsxFragmentFactory && !nodeSourceFile.pragmas.has("jsxfrag")) {
error(node, compilerOptions.jsxFactory
? Diagnostics.The_jsxFragmentFactory_compiler_option_must_be_provided_to_use_JSX_fragments_with_the_jsxFactory_compiler_option
Expand Down Expand Up @@ -37330,6 +37330,9 @@ namespace ts {
// When resolved as an expression identifier, if the given node references an import, return the declaration of
// that import. Otherwise, return undefined.
function getReferencedImportDeclaration(nodeIn: Identifier): Declaration | undefined {
if (nodeIn.generatedImportReference) {
return nodeIn.generatedImportReference;
}
const node = getParseTreeNode(nodeIn, isIdentifier);
if (node) {
const symbol = getReferencedValueSymbol(node);
Expand Down
23 changes: 18 additions & 5 deletions src/compiler/commandLineParser.ts
Expand Up @@ -2,6 +2,17 @@ namespace ts {
/* @internal */
export const compileOnSaveCommandLineOption: CommandLineOption = { name: "compileOnSave", type: "boolean" };

const jsxOptionMap = new Map(getEntries({
"preserve": JsxEmit.Preserve,
"react-native": JsxEmit.ReactNative,
"react": JsxEmit.React,
"react-jsx": JsxEmit.ReactJSX,
"react-jsxdev": JsxEmit.ReactJSXDev,
}));

/* @internal */
export const inverseJsxOptionMap = new Map(arrayFrom(mapIterator(jsxOptionMap.entries(), ([key, value]: [string, JsxEmit]) => ["" + value, key] as const)));

// NOTE: The order here is important to default lib ordering as entries will have the same
// order in the generated program (see `getDefaultLibPriority` in program.ts). This
// order also affects overload resolution when a type declared in one lib is
Expand Down Expand Up @@ -366,11 +377,7 @@ namespace ts {
},
{
name: "jsx",
type: new Map(getEntries({
"preserve": JsxEmit.Preserve,
"react-native": JsxEmit.ReactNative,
"react": JsxEmit.React
})),
type: jsxOptionMap,
affectsSourceFile: true,
paramType: Diagnostics.KIND,
showInSimplifiedHelpView: true,
Expand Down Expand Up @@ -781,6 +788,12 @@ namespace ts {
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: "jsxImportSource",
type: "string",
category: Diagnostics.Advanced_Options,
description: Diagnostics.Specify_the_module_specifier_to_be_used_to_import_the_jsx_and_jsxs_factory_functions_from_eg_react
},
{
name: "resolveJsonModule",
type: "boolean",
Expand Down
8 changes: 8 additions & 0 deletions src/compiler/diagnosticMessages.json
Expand Up @@ -3609,6 +3609,10 @@
"category": "Error",
"code": 5088
},
"Option '{0}' cannot be specified when option 'jsx' is '{1}'.": {
"category": "Error",
"code": 5089
},

"Generates a sourcemap for each corresponding '.d.ts' file.": {
"category": "Message",
Expand Down Expand Up @@ -4508,6 +4512,10 @@
"category": "Message",
"code": 6237
},
"Specify the module specifier to be used to import the `jsx` and `jsxs` factory functions from. eg, react": {
"category": "Error",
"code": 6238
},

"Projects to reference": {
"category": "Message",
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/parser.ts
Expand Up @@ -8879,6 +8879,8 @@ namespace ts {
}
case "jsx":
case "jsxfrag":
case "jsximportsource":
case "jsxruntime":
return; // Accessed directly
default: Debug.fail("Unhandled pragma kind"); // Can this be made into an assertNever in the future?
}
Expand Down
18 changes: 18 additions & 0 deletions src/compiler/program.ts
Expand Up @@ -3196,6 +3196,9 @@ namespace ts {
if (options.reactNamespace) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "reactNamespace", "jsxFactory");
}
if (options.jsx === JsxEmit.ReactJSX || options.jsx === JsxEmit.ReactJSXDev) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, "jsxFactory", inverseJsxOptionMap.get("" + options.jsx));
}
if (!parseIsolatedEntityName(options.jsxFactory, languageVersion)) {
createOptionValueDiagnostic("jsxFactory", Diagnostics.Invalid_value_for_jsxFactory_0_is_not_a_valid_identifier_or_qualified_name, options.jsxFactory);
}
Expand All @@ -3208,11 +3211,26 @@ namespace ts {
if (!options.jsxFactory) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "jsxFragmentFactory", "jsxFactory");
}
if (options.jsx === JsxEmit.ReactJSX || options.jsx === JsxEmit.ReactJSXDev) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, "jsxFragmentFactory", inverseJsxOptionMap.get("" + options.jsx));
}
if (!parseIsolatedEntityName(options.jsxFragmentFactory, languageVersion)) {
createOptionValueDiagnostic("jsxFragmentFactory", Diagnostics.Invalid_value_for_jsxFragmentFactory_0_is_not_a_valid_identifier_or_qualified_name, options.jsxFragmentFactory);
}
}

if (options.reactNamespace) {
if (options.jsx === JsxEmit.ReactJSX || options.jsx === JsxEmit.ReactJSXDev) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, "reactNamespace", inverseJsxOptionMap.get("" + options.jsx));
}
}

if (options.jsxImportSource) {
if (options.jsx === JsxEmit.React) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, "jsxImportSource", inverseJsxOptionMap.get("" + options.jsx));
}
}

// 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();
Expand Down
3 changes: 1 addition & 2 deletions src/compiler/transformer.ts
Expand Up @@ -37,7 +37,6 @@ namespace ts {
function getScriptTransformers(compilerOptions: CompilerOptions, customTransformers?: CustomTransformers, emitOnlyDtsFiles?: boolean) {
if (emitOnlyDtsFiles) return emptyArray;

const jsx = compilerOptions.jsx;
const languageVersion = getEmitScriptTarget(compilerOptions);
const moduleKind = getEmitModuleKind(compilerOptions);
const transformers: TransformerFactory<SourceFile | Bundle>[] = [];
Expand All @@ -47,7 +46,7 @@ namespace ts {
transformers.push(transformTypeScript);
transformers.push(transformClassFields);

if (jsx === JsxEmit.React) {
if (getJSXTransformEnabled(compilerOptions)) {
transformers.push(transformJsx);
}

Expand Down