1/*@internal*/ 2namespace ts { 3 /** 4 * Transforms ES5 syntax into ES3 syntax. 5 * 6 * @param context Context and state information for the transformation. 7 */ 8 export function transformES5(context: TransformationContext) { 9 const { factory } = context; 10 const compilerOptions = context.getCompilerOptions(); 11 12 // enable emit notification only if using --jsx preserve or react-native 13 let previousOnEmitNode: (hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) => void; 14 let noSubstitution: boolean[]; 15 if (compilerOptions.jsx === JsxEmit.Preserve || compilerOptions.jsx === JsxEmit.ReactNative) { 16 previousOnEmitNode = context.onEmitNode; 17 context.onEmitNode = onEmitNode; 18 context.enableEmitNotification(SyntaxKind.JsxOpeningElement); 19 context.enableEmitNotification(SyntaxKind.JsxClosingElement); 20 context.enableEmitNotification(SyntaxKind.JsxSelfClosingElement); 21 noSubstitution = []; 22 } 23 24 const previousOnSubstituteNode = context.onSubstituteNode; 25 context.onSubstituteNode = onSubstituteNode; 26 context.enableSubstitution(SyntaxKind.PropertyAccessExpression); 27 context.enableSubstitution(SyntaxKind.PropertyAssignment); 28 return chainBundle(context, transformSourceFile); 29 30 /** 31 * Transforms an ES5 source file to ES3. 32 * 33 * @param node A SourceFile 34 */ 35 function transformSourceFile(node: SourceFile) { 36 return node; 37 } 38 39 /** 40 * Called by the printer just before a node is printed. 41 * 42 * @param hint A hint as to the intended usage of the node. 43 * @param node The node to emit. 44 * @param emitCallback A callback used to emit the node. 45 */ 46 function onEmitNode(hint: EmitHint, node: Node, emitCallback: (emitContext: EmitHint, node: Node) => void) { 47 switch (node.kind) { 48 case SyntaxKind.JsxOpeningElement: 49 case SyntaxKind.JsxClosingElement: 50 case SyntaxKind.JsxSelfClosingElement: 51 const tagName = (node as JsxOpeningElement | JsxClosingElement | JsxSelfClosingElement).tagName; 52 noSubstitution[getOriginalNodeId(tagName)] = true; 53 break; 54 } 55 56 previousOnEmitNode(hint, node, emitCallback); 57 } 58 59 /** 60 * Hooks node substitutions. 61 * 62 * @param hint A hint as to the intended usage of the node. 63 * @param node The node to substitute. 64 */ 65 function onSubstituteNode(hint: EmitHint, node: Node) { 66 if (node.id && noSubstitution && noSubstitution[node.id]) { 67 return previousOnSubstituteNode(hint, node); 68 } 69 70 node = previousOnSubstituteNode(hint, node); 71 if (isPropertyAccessExpression(node)) { 72 return substitutePropertyAccessExpression(node); 73 } 74 else if (isPropertyAssignment(node)) { 75 return substitutePropertyAssignment(node); 76 } 77 return node; 78 } 79 80 /** 81 * Substitutes a PropertyAccessExpression whose name is a reserved word. 82 * 83 * @param node A PropertyAccessExpression 84 */ 85 function substitutePropertyAccessExpression(node: PropertyAccessExpression): Expression { 86 if (isPrivateIdentifier(node.name)) { 87 return node; 88 } 89 const literalName = trySubstituteReservedName(node.name); 90 if (literalName) { 91 return setTextRange(factory.createElementAccessExpression(node.expression, literalName), node); 92 } 93 return node; 94 } 95 96 /** 97 * Substitutes a PropertyAssignment whose name is a reserved word. 98 * 99 * @param node A PropertyAssignment 100 */ 101 function substitutePropertyAssignment(node: PropertyAssignment): PropertyAssignment { 102 const literalName = isIdentifier(node.name) && trySubstituteReservedName(node.name); 103 if (literalName) { 104 return factory.updatePropertyAssignment(node, literalName, node.initializer); 105 } 106 return node; 107 } 108 109 /** 110 * If an identifier name is a reserved word, returns a string literal for the name. 111 * 112 * @param name An Identifier 113 */ 114 function trySubstituteReservedName(name: Identifier) { 115 const token = name.originalKeywordKind || (nodeIsSynthesized(name) ? stringToToken(idText(name)) : undefined); 116 if (token !== undefined && token >= SyntaxKind.FirstReservedWord && token <= SyntaxKind.LastReservedWord) { 117 return setTextRange(factory.createStringLiteralFromNode(name), name); 118 } 119 return undefined; 120 } 121 } 122} 123