From c77eb0aa4ce7e88456c8710bff88fdd6e68b3c7c Mon Sep 17 00:00:00 2001 From: GlassBricks <24237065+GlassBricks@users.noreply.github.com> Date: Sun, 5 Sep 2021 16:46:38 -0700 Subject: [PATCH 1/2] Use `ts.transformJsx` instead for jsx. Reverts "JSX support (#1052)". This reverts commit 987899c8acdaf14668d234a8470c9f29a33f7459. --- src/transformation/utils/annotations.ts | 2 - src/transformation/visitors/index.ts | 2 - src/transformation/visitors/jsx/jsx.ts | 264 ------------------ src/transformation/visitors/jsx/xhtml.ts | 256 ----------------- .../visitors/language-extensions/multi.ts | 2 +- src/transformation/visitors/literal.ts | 142 ++++------ src/transpilation/transformers.ts | 65 +++-- src/typescript-internal.d.ts | 2 + test/unit/jsx.spec.ts | 12 +- 9 files changed, 107 insertions(+), 640 deletions(-) delete mode 100644 src/transformation/visitors/jsx/jsx.ts delete mode 100644 src/transformation/visitors/jsx/xhtml.ts diff --git a/src/transformation/utils/annotations.ts b/src/transformation/utils/annotations.ts index 7f7b19652..2b2309941 100644 --- a/src/transformation/utils/annotations.ts +++ b/src/transformation/utils/annotations.ts @@ -16,8 +16,6 @@ export enum AnnotationKind { NoSelfInFile = "noSelfInFile", Vararg = "vararg", ForRange = "forRange", - Jsx = "jsx", - JsxFrag = "jsxFrag", } export interface Annotation { diff --git a/src/transformation/visitors/index.ts b/src/transformation/visitors/index.ts index 28f965932..f6bb8b697 100644 --- a/src/transformation/visitors/index.ts +++ b/src/transformation/visitors/index.ts @@ -40,7 +40,6 @@ import { transformTypeOfExpression } from "./typeof"; import { typescriptVisitors } from "./typescript"; import { transformPostfixUnaryExpression, transformPrefixUnaryExpression } from "./unary-expression"; import { transformVariableStatement } from "./variable-declaration"; -import { jsxVisitors } from "./jsx/jsx"; import { transformAwaitExpression } from "./async-await"; const transformEmptyStatement: FunctionVisitor = () => undefined; @@ -50,7 +49,6 @@ const transformParenthesizedExpression: FunctionVisitor= charCodes.a && ch <= charCodes.z) || name.includes("-") || name.includes(":"); -} - -function transformTagName(name: ts.JsxTagNameExpression, context: TransformationContext): lua.Expression { - if (ts.isIdentifier(name) && isIntrinsicJsxName(name.escapedText)) { - return lua.createStringLiteral(ts.idText(name), name); - } else { - return context.transformExpression(name); - } -} - -function transformJsxChildren( - children: ts.NodeArray | undefined, - context: TransformationContext -): lua.Expression[] | undefined { - if (!children) return undefined; - - return children - .map(child => { - if (ts.isJsxText(child)) { - return processJsxText(child); - } - if (ts.isJsxExpression(child)) { - return child.expression; - } - return child; - }) - .filter(child => child !== undefined) - .map(child => context.transformExpression(child!)); -} - -function createJsxFactoryCall( - tagName: lua.Expression, - props: lua.Expression | undefined, - tsChildren: ts.NodeArray | undefined, - tsOriginal: ts.Node, - context: TransformationContext -): lua.Expression { - const transformedChildren = transformJsxChildren(tsChildren, context); - const jsxFactory = getJsxFactory(tsOriginal, context); - - const args = [tagName]; - if (props) { - args.push(props); - } - if (transformedChildren && transformedChildren.length > 0) { - if (!props) { - args.push(lua.createNilLiteral()); - } - args.push(...transformedChildren); - } - return lua.createCallExpression(jsxFactory, args, tsOriginal); -} - -function transformJsxOpeningLikeElement( - node: ts.JsxOpeningLikeElement, - children: ts.NodeArray | undefined, - context: TransformationContext -): lua.Expression { - const tagName = transformTagName(node.tagName, context); - const props = - node.attributes.properties.length !== 0 ? transformJsxAttributes(node.attributes, context) : undefined; - - return createJsxFactoryCall(tagName, props, children, node, context); -} - -const transformJsxElement: FunctionVisitor = (node, context) => - transformJsxOpeningLikeElement(node.openingElement, node.children, context); -const transformSelfClosingJsxElement: FunctionVisitor = (node, context) => - transformJsxOpeningLikeElement(node, undefined, context); -const transformJsxFragment: FunctionVisitor = (node, context) => { - const tagName = getJsxFragmentName(node, context); - return createJsxFactoryCall(tagName, undefined, node.children, node, context); -}; - -export const jsxVisitors: Visitors = { - [ts.SyntaxKind.JsxElement]: transformJsxElement, - [ts.SyntaxKind.JsxSelfClosingElement]: transformSelfClosingJsxElement, - [ts.SyntaxKind.JsxFragment]: transformJsxFragment, -}; diff --git a/src/transformation/visitors/jsx/xhtml.ts b/src/transformation/visitors/jsx/xhtml.ts deleted file mode 100644 index 814191df0..000000000 --- a/src/transformation/visitors/jsx/xhtml.ts +++ /dev/null @@ -1,256 +0,0 @@ -/* eslint-disable @typescript-eslint/naming-convention */ -export const XHTMLEntities: { [name: string]: string } = { - quot: "\u0022", - amp: "&", - apos: "\u0027", - lt: "<", - gt: ">", - nbsp: "\u00A0", - iexcl: "\u00A1", - cent: "\u00A2", - pound: "\u00A3", - curren: "\u00A4", - yen: "\u00A5", - brvbar: "\u00A6", - sect: "\u00A7", - uml: "\u00A8", - copy: "\u00A9", - ordf: "\u00AA", - laquo: "\u00AB", - not: "\u00AC", - shy: "\u00AD", - reg: "\u00AE", - macr: "\u00AF", - deg: "\u00B0", - plusmn: "\u00B1", - sup2: "\u00B2", - sup3: "\u00B3", - acute: "\u00B4", - micro: "\u00B5", - para: "\u00B6", - middot: "\u00B7", - cedil: "\u00B8", - sup1: "\u00B9", - ordm: "\u00BA", - raquo: "\u00BB", - frac14: "\u00BC", - frac12: "\u00BD", - frac34: "\u00BE", - iquest: "\u00BF", - Agrave: "\u00C0", - Aacute: "\u00C1", - Acirc: "\u00C2", - Atilde: "\u00C3", - Auml: "\u00C4", - Aring: "\u00C5", - AElig: "\u00C6", - Ccedil: "\u00C7", - Egrave: "\u00C8", - Eacute: "\u00C9", - Ecirc: "\u00CA", - Euml: "\u00CB", - Igrave: "\u00CC", - Iacute: "\u00CD", - Icirc: "\u00CE", - Iuml: "\u00CF", - ETH: "\u00D0", - Ntilde: "\u00D1", - Ograve: "\u00D2", - Oacute: "\u00D3", - Ocirc: "\u00D4", - Otilde: "\u00D5", - Ouml: "\u00D6", - times: "\u00D7", - Oslash: "\u00D8", - Ugrave: "\u00D9", - Uacute: "\u00DA", - Ucirc: "\u00DB", - Uuml: "\u00DC", - Yacute: "\u00DD", - THORN: "\u00DE", - szlig: "\u00DF", - agrave: "\u00E0", - aacute: "\u00E1", - acirc: "\u00E2", - atilde: "\u00E3", - auml: "\u00E4", - aring: "\u00E5", - aelig: "\u00E6", - ccedil: "\u00E7", - egrave: "\u00E8", - eacute: "\u00E9", - ecirc: "\u00EA", - euml: "\u00EB", - igrave: "\u00EC", - iacute: "\u00ED", - icirc: "\u00EE", - iuml: "\u00EF", - eth: "\u00F0", - ntilde: "\u00F1", - ograve: "\u00F2", - oacute: "\u00F3", - ocirc: "\u00F4", - otilde: "\u00F5", - ouml: "\u00F6", - divide: "\u00F7", - oslash: "\u00F8", - ugrave: "\u00F9", - uacute: "\u00FA", - ucirc: "\u00FB", - uuml: "\u00FC", - yacute: "\u00FD", - thorn: "\u00FE", - yuml: "\u00FF", - OElig: "\u0152", - oelig: "\u0153", - Scaron: "\u0160", - scaron: "\u0161", - Yuml: "\u0178", - fnof: "\u0192", - circ: "\u02C6", - tilde: "\u02DC", - Alpha: "\u0391", - Beta: "\u0392", - Gamma: "\u0393", - Delta: "\u0394", - Epsilon: "\u0395", - Zeta: "\u0396", - Eta: "\u0397", - Theta: "\u0398", - Iota: "\u0399", - Kappa: "\u039A", - Lambda: "\u039B", - Mu: "\u039C", - Nu: "\u039D", - Xi: "\u039E", - Omicron: "\u039F", - Pi: "\u03A0", - Rho: "\u03A1", - Sigma: "\u03A3", - Tau: "\u03A4", - Upsilon: "\u03A5", - Phi: "\u03A6", - Chi: "\u03A7", - Psi: "\u03A8", - Omega: "\u03A9", - alpha: "\u03B1", - beta: "\u03B2", - gamma: "\u03B3", - delta: "\u03B4", - epsilon: "\u03B5", - zeta: "\u03B6", - eta: "\u03B7", - theta: "\u03B8", - iota: "\u03B9", - kappa: "\u03BA", - lambda: "\u03BB", - mu: "\u03BC", - nu: "\u03BD", - xi: "\u03BE", - omicron: "\u03BF", - pi: "\u03C0", - rho: "\u03C1", - sigmaf: "\u03C2", - sigma: "\u03C3", - tau: "\u03C4", - upsilon: "\u03C5", - phi: "\u03C6", - chi: "\u03C7", - psi: "\u03C8", - omega: "\u03C9", - thetasym: "\u03D1", - upsih: "\u03D2", - piv: "\u03D6", - ensp: "\u2002", - emsp: "\u2003", - thinsp: "\u2009", - zwnj: "\u200C", - zwj: "\u200D", - lrm: "\u200E", - rlm: "\u200F", - ndash: "\u2013", - mdash: "\u2014", - lsquo: "\u2018", - rsquo: "\u2019", - sbquo: "\u201A", - ldquo: "\u201C", - rdquo: "\u201D", - bdquo: "\u201E", - dagger: "\u2020", - Dagger: "\u2021", - bull: "\u2022", - hellip: "\u2026", - permil: "\u2030", - prime: "\u2032", - Prime: "\u2033", - lsaquo: "\u2039", - rsaquo: "\u203A", - oline: "\u203E", - frasl: "\u2044", - euro: "\u20AC", - image: "\u2111", - weierp: "\u2118", - real: "\u211C", - trade: "\u2122", - alefsym: "\u2135", - larr: "\u2190", - uarr: "\u2191", - rarr: "\u2192", - darr: "\u2193", - harr: "\u2194", - crarr: "\u21B5", - lArr: "\u21D0", - uArr: "\u21D1", - rArr: "\u21D2", - dArr: "\u21D3", - hArr: "\u21D4", - forall: "\u2200", - part: "\u2202", - exist: "\u2203", - empty: "\u2205", - nabla: "\u2207", - isin: "\u2208", - notin: "\u2209", - ni: "\u220B", - prod: "\u220F", - sum: "\u2211", - minus: "\u2212", - lowast: "\u2217", - radic: "\u221A", - prop: "\u221D", - infin: "\u221E", - ang: "\u2220", - and: "\u2227", - or: "\u2228", - cap: "\u2229", - cup: "\u222A", - int: "\u222B", - there4: "\u2234", - sim: "\u223C", - cong: "\u2245", - asymp: "\u2248", - ne: "\u2260", - equiv: "\u2261", - le: "\u2264", - ge: "\u2265", - sub: "\u2282", - sup: "\u2283", - nsub: "\u2284", - sube: "\u2286", - supe: "\u2287", - oplus: "\u2295", - otimes: "\u2297", - perp: "\u22A5", - sdot: "\u22C5", - lceil: "\u2308", - rceil: "\u2309", - lfloor: "\u230A", - rfloor: "\u230B", - lang: "\u2329", - rang: "\u232A", - loz: "\u25CA", - spades: "\u2660", - clubs: "\u2663", - hearts: "\u2665", - diams: "\u2666", -}; diff --git a/src/transformation/visitors/language-extensions/multi.ts b/src/transformation/visitors/language-extensions/multi.ts index a1c9c4030..caaae7470 100644 --- a/src/transformation/visitors/language-extensions/multi.ts +++ b/src/transformation/visitors/language-extensions/multi.ts @@ -94,7 +94,7 @@ export function shouldMultiReturnCallBeWrapped(context: TransformationContext, n export function findMultiAssignmentViolations( context: TransformationContext, - node: ts.ObjectLiteralExpressionBase + node: ts.ObjectLiteralExpression ): ts.Node[] { const result: ts.Node[] = []; diff --git a/src/transformation/visitors/literal.ts b/src/transformation/visitors/literal.ts index 75b4a3224..c0e9a6256 100644 --- a/src/transformation/visitors/literal.ts +++ b/src/transformation/visitors/literal.ts @@ -11,7 +11,6 @@ import { isArrayType } from "../utils/typescript"; import { transformFunctionLikeDeclaration } from "./function"; import { flattenSpreadExpressions } from "./call"; import { findMultiAssignmentViolations } from "./language-extensions/multi"; -import { formatJSXStringValueLiteral } from "./jsx/jsx"; // TODO: Move to object-literal.ts? export function transformPropertyName(context: TransformationContext, node: ts.PropertyName): lua.Expression { @@ -63,99 +62,78 @@ const transformNumericLiteralExpression: FunctionVisitor = ex return lua.createNumericLiteral(Number(expression.text), expression); }; -const transformObjectLiteralExpressionOrJsxAttributes: FunctionVisitor = - (expression, context) => { - const violations = findMultiAssignmentViolations(context, expression); - if (violations.length > 0) { - context.diagnostics.push(...violations.map(e => invalidMultiFunctionUse(e))); - return lua.createNilLiteral(expression); - } +const transformObjectLiteralExpression: FunctionVisitor = (expression, context) => { + const violations = findMultiAssignmentViolations(context, expression); + if (violations.length > 0) { + context.diagnostics.push(...violations.map(e => invalidMultiFunctionUse(e))); + return lua.createNilLiteral(expression); + } - let properties: lua.TableFieldExpression[] = []; - const tableExpressions: lua.Expression[] = []; - - for (const element of expression.properties) { - const name = element.name ? transformPropertyName(context, element.name) : undefined; - - if (ts.isPropertyAssignment(element)) { - const expression = context.transformExpression(element.initializer); - properties.push(lua.createTableFieldExpression(expression, name, element)); - } else if (ts.isJsxAttribute(element)) { - const initializer = element.initializer; - let expression: lua.Expression; - if (initializer === undefined) { - expression = lua.createBooleanLiteral(true); - } else if (ts.isStringLiteral(initializer)) { - const text = formatJSXStringValueLiteral(initializer.text); - expression = lua.createStringLiteral(text, initializer); - } else if (ts.isJsxExpression(initializer)) { - expression = initializer.expression - ? context.transformExpression(initializer.expression) - : lua.createBooleanLiteral(true); - } else { - assertNever(initializer); - } - properties.push(lua.createTableFieldExpression(expression, name, element)); - } else if (ts.isShorthandPropertyAssignment(element)) { - const valueSymbol = context.checker.getShorthandAssignmentValueSymbol(element); - if (valueSymbol) { - trackSymbolReference(context, valueSymbol, element.name); - } - - const identifier = createShorthandIdentifier(context, valueSymbol, element.name); - properties.push(lua.createTableFieldExpression(identifier, name, element)); - } else if (ts.isMethodDeclaration(element)) { - const expression = transformFunctionLikeDeclaration(element, context); - properties.push(lua.createTableFieldExpression(expression, name, element)); - } else if (ts.isSpreadAssignment(element) || ts.isJsxSpreadAttribute(element)) { - // Create a table for preceding properties to preserve property order - // { x: 0, ...{ y: 2 }, y: 1, z: 2 } --> __TS__ObjectAssign({x = 0}, {y = 2}, {y = 1, z = 2}) - if (properties.length > 0) { - const tableExpression = lua.createTableExpression(properties, expression); - tableExpressions.push(tableExpression); - properties = []; - } - - const type = context.checker.getTypeAtLocation(element.expression); - let tableExpression: lua.Expression; - if (isArrayType(context, type)) { - tableExpression = transformLuaLibFunction( - context, - LuaLibFeature.ArrayToObject, - element.expression, - context.transformExpression(element.expression) - ); - } else { - tableExpression = context.transformExpression(element.expression); - } + let properties: lua.TableFieldExpression[] = []; + const tableExpressions: lua.Expression[] = []; - tableExpressions.push(tableExpression); - } else if (ts.isAccessor(element)) { - context.diagnostics.push(unsupportedAccessorInObjectLiteral(element)); - } else { - assertNever(element); + for (const element of expression.properties) { + const name = element.name ? transformPropertyName(context, element.name) : undefined; + + if (ts.isPropertyAssignment(element)) { + const expression = context.transformExpression(element.initializer); + properties.push(lua.createTableFieldExpression(expression, name, element)); + } else if (ts.isShorthandPropertyAssignment(element)) { + const valueSymbol = context.checker.getShorthandAssignmentValueSymbol(element); + if (valueSymbol) { + trackSymbolReference(context, valueSymbol, element.name); } - } - if (tableExpressions.length === 0) { - return lua.createTableExpression(properties, expression); - } else { + const identifier = createShorthandIdentifier(context, valueSymbol, element.name); + properties.push(lua.createTableFieldExpression(identifier, name, element)); + } else if (ts.isMethodDeclaration(element)) { + const expression = transformFunctionLikeDeclaration(element, context); + properties.push(lua.createTableFieldExpression(expression, name, element)); + } else if (ts.isSpreadAssignment(element)) { + // Create a table for preceding properties to preserve property order + // { x: 0, ...{ y: 2 }, y: 1, z: 2 } --> __TS__ObjectAssign({x = 0}, {y = 2}, {y = 1, z = 2}) if (properties.length > 0) { const tableExpression = lua.createTableExpression(properties, expression); tableExpressions.push(tableExpression); + properties = []; } - if (tableExpressions[0].kind !== lua.SyntaxKind.TableExpression) { - tableExpressions.unshift(lua.createTableExpression(undefined, expression)); + const type = context.checker.getTypeAtLocation(element.expression); + let tableExpression: lua.Expression; + if (isArrayType(context, type)) { + tableExpression = transformLuaLibFunction( + context, + LuaLibFeature.ArrayToObject, + element.expression, + context.transformExpression(element.expression) + ); + } else { + tableExpression = context.transformExpression(element.expression); } - return transformLuaLibFunction(context, LuaLibFeature.ObjectAssign, expression, ...tableExpressions); + tableExpressions.push(tableExpression); + } else if (ts.isAccessor(element)) { + context.diagnostics.push(unsupportedAccessorInObjectLiteral(element)); + } else { + assertNever(element); + } + } + + if (tableExpressions.length === 0) { + return lua.createTableExpression(properties, expression); + } else { + if (properties.length > 0) { + const tableExpression = lua.createTableExpression(properties, expression); + tableExpressions.push(tableExpression); } - }; -const transformObjectLiteralExpression: FunctionVisitor = - transformObjectLiteralExpressionOrJsxAttributes; -export const transformJsxAttributes: FunctionVisitor = - transformObjectLiteralExpressionOrJsxAttributes; + + if (tableExpressions[0].kind !== lua.SyntaxKind.TableExpression) { + tableExpressions.unshift(lua.createTableExpression(undefined, expression)); + } + + return transformLuaLibFunction(context, LuaLibFeature.ObjectAssign, expression, ...tableExpressions); + } +}; const transformArrayLiteralExpression: FunctionVisitor = (expression, context) => { const filteredElements = expression.elements.map(e => diff --git a/src/transpilation/transformers.ts b/src/transpilation/transformers.ts index 7b5aacddd..dcd746847 100644 --- a/src/transpilation/transformers.ts +++ b/src/transpilation/transformers.ts @@ -86,40 +86,51 @@ function loadTransformersFromOptions(program: ts.Program, diagnostics: ts.Diagno }; const options = program.getCompilerOptions() as CompilerOptions; - if (!options.plugins) return customTransformers; - - for (const [index, transformerImport] of options.plugins.entries()) { - if (!("transform" in transformerImport)) continue; - const optionName = `compilerOptions.plugins[${index}]`; + if (options.plugins) { + for (const [index, transformerImport] of options.plugins.entries()) { + if (!("transform" in transformerImport)) continue; + const optionName = `compilerOptions.plugins[${index}]`; + + const { error: resolveError, result: factory } = resolvePlugin( + "transformer", + `${optionName}.transform`, + getConfigDirectory(options), + transformerImport.transform, + transformerImport.import + ); - const { error: resolveError, result: factory } = resolvePlugin( - "transformer", - `${optionName}.transform`, - getConfigDirectory(options), - transformerImport.transform, - transformerImport.import - ); + if (resolveError) diagnostics.push(resolveError); + if (factory === undefined) continue; - if (resolveError) diagnostics.push(resolveError); - if (factory === undefined) continue; + const { error: loadError, transformer } = loadTransformer(optionName, program, factory, transformerImport); + if (loadError) diagnostics.push(loadError); + if (transformer === undefined) continue; - const { error: loadError, transformer } = loadTransformer(optionName, program, factory, transformerImport); - if (loadError) diagnostics.push(loadError); - if (transformer === undefined) continue; + if (transformer.before) { + customTransformers.before.push(transformer.before); + } - if (transformer.before) { - customTransformers.before.push(transformer.before); - } + if (transformer.after) { + customTransformers.after.push(transformer.after); + } - if (transformer.after) { - customTransformers.after.push(transformer.after); - } - - if (transformer.afterDeclarations) { - customTransformers.afterDeclarations.push(transformer.afterDeclarations); + if (transformer.afterDeclarations) { + customTransformers.afterDeclarations.push(transformer.afterDeclarations); + } } } - + if (options.jsx === ts.JsxEmit.React) { + customTransformers.before.push(context => { + const patchedContext: ts.TransformationContext = { + ...context, + getCompilerOptions: () => ({ + ...context.getCompilerOptions(), + target: ts.ScriptTarget.ESNext, + }), + }; + return ts.transformJsx(patchedContext); + }); + } return customTransformers; } diff --git a/src/typescript-internal.d.ts b/src/typescript-internal.d.ts index 8fd8fd1ec..3fde219f5 100644 --- a/src/typescript-internal.d.ts +++ b/src/typescript-internal.d.ts @@ -28,4 +28,6 @@ declare module "typescript" { getElementTypeOfArrayType(type: Type): Type | undefined; getContextualTypeForObjectLiteralElement(element: ObjectLiteralElementLike): Type | undefined; } + + function transformJsx(context: TransformationContext): (x: SourceFile) => SourceFile; } diff --git a/test/unit/jsx.spec.ts b/test/unit/jsx.spec.ts index 5734b33ee..37cdc14c5 100644 --- a/test/unit/jsx.spec.ts +++ b/test/unit/jsx.spec.ts @@ -12,7 +12,6 @@ const reactLib = ` const isLua = typeof Component === "object" export function createElement( - this: void, type: any, props?: any, ...children: any[] @@ -21,11 +20,13 @@ const reactLib = ` if (isLua) { typeStr = typeof type === "function" ? "<< function >>" : - typeof type === "object" ? \`<< class \${type.name} >>\` : - type + typeof type === "object" ? \`<< class \${type.name} >>\` : + type } else { - typeStr = typeof type === "function" ? (type.isClass ? \`<< class \${type.name} >>\` : "<< function >>") - : type + typeStr = typeof type === "function" ? (type.isClass + ? \`<< class \${type.name} >>\` + : "<< function >>") + : type } return { @@ -259,7 +260,6 @@ describe("jsx", () => { // language=TypeScript const customJsxLib = `export namespace MyLib { export function myCreate( - this: void, type: any, props: any, ...children: any[] From cc23af7eb3e1822bfa44e0dd815d7ced2dd68dd7 Mon Sep 17 00:00:00 2001 From: GlassBricks <24237065+GlassBricks@users.noreply.github.com> Date: Tue, 7 Sep 2021 21:41:22 -0700 Subject: [PATCH 2/2] Add comment explaining overriding compiler options --- src/transpilation/transformers.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/transpilation/transformers.ts b/src/transpilation/transformers.ts index dcd746847..386d7f475 100644 --- a/src/transpilation/transformers.ts +++ b/src/transpilation/transformers.ts @@ -121,6 +121,8 @@ function loadTransformersFromOptions(program: ts.Program, diagnostics: ts.Diagno } if (options.jsx === ts.JsxEmit.React) { customTransformers.before.push(context => { + // if target < ES2017, typescript generates some unnecessary additional transformations in transformJSX. + // We can't control the target compiler option, so we override here. const patchedContext: ts.TransformationContext = { ...context, getCompilerOptions: () => ({