Revision 79244c578fe473f3b9c2537d70f9ad86d71a9dc9 authored by Oleksandr T on 30 December 2022, 16:57:33 UTC, committed by GitHub on 30 December 2022, 16:57:33 UTC
1 parent 44152bc
es5.ts
import {
Bundle,
chainBundle,
EmitHint,
Expression,
getOriginalNodeId,
Identifier,
idText,
isIdentifier,
isPrivateIdentifier,
isPropertyAccessExpression,
isPropertyAssignment,
JsxClosingElement,
JsxEmit,
JsxOpeningElement,
JsxSelfClosingElement,
Node,
nodeIsSynthesized,
PropertyAccessExpression,
PropertyAssignment,
setTextRange,
SourceFile,
stringToToken,
SyntaxKind,
TransformationContext,
} from "../_namespaces/ts";
/**
* Transforms ES5 syntax into ES3 syntax.
*
* @param context Context and state information for the transformation.
*
* @internal
*/
export function transformES5(context: TransformationContext): (x: SourceFile | Bundle) => SourceFile | Bundle {
const { factory } = context;
const compilerOptions = context.getCompilerOptions();
// enable emit notification only if using --jsx preserve or react-native
let previousOnEmitNode: (hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) => void;
let noSubstitution: boolean[];
if (compilerOptions.jsx === JsxEmit.Preserve || compilerOptions.jsx === JsxEmit.ReactNative) {
previousOnEmitNode = context.onEmitNode;
context.onEmitNode = onEmitNode;
context.enableEmitNotification(SyntaxKind.JsxOpeningElement);
context.enableEmitNotification(SyntaxKind.JsxClosingElement);
context.enableEmitNotification(SyntaxKind.JsxSelfClosingElement);
noSubstitution = [];
}
const previousOnSubstituteNode = context.onSubstituteNode;
context.onSubstituteNode = onSubstituteNode;
context.enableSubstitution(SyntaxKind.PropertyAccessExpression);
context.enableSubstitution(SyntaxKind.PropertyAssignment);
return chainBundle(context, transformSourceFile);
/**
* Transforms an ES5 source file to ES3.
*
* @param node A SourceFile
*/
function transformSourceFile(node: SourceFile) {
return node;
}
/**
* Called by the printer just before a node is printed.
*
* @param hint A hint as to the intended usage of the node.
* @param node The node to emit.
* @param emitCallback A callback used to emit the node.
*/
function onEmitNode(hint: EmitHint, node: Node, emitCallback: (emitContext: EmitHint, node: Node) => void) {
switch (node.kind) {
case SyntaxKind.JsxOpeningElement:
case SyntaxKind.JsxClosingElement:
case SyntaxKind.JsxSelfClosingElement:
const tagName = (node as JsxOpeningElement | JsxClosingElement | JsxSelfClosingElement).tagName;
noSubstitution[getOriginalNodeId(tagName)] = true;
break;
}
previousOnEmitNode(hint, node, emitCallback);
}
/**
* Hooks node substitutions.
*
* @param hint A hint as to the intended usage of the node.
* @param node The node to substitute.
*/
function onSubstituteNode(hint: EmitHint, node: Node) {
if (node.id && noSubstitution && noSubstitution[node.id]) {
return previousOnSubstituteNode(hint, node);
}
node = previousOnSubstituteNode(hint, node);
if (isPropertyAccessExpression(node)) {
return substitutePropertyAccessExpression(node);
}
else if (isPropertyAssignment(node)) {
return substitutePropertyAssignment(node);
}
return node;
}
/**
* Substitutes a PropertyAccessExpression whose name is a reserved word.
*
* @param node A PropertyAccessExpression
*/
function substitutePropertyAccessExpression(node: PropertyAccessExpression): Expression {
if (isPrivateIdentifier(node.name)) {
return node;
}
const literalName = trySubstituteReservedName(node.name);
if (literalName) {
return setTextRange(factory.createElementAccessExpression(node.expression, literalName), node);
}
return node;
}
/**
* Substitutes a PropertyAssignment whose name is a reserved word.
*
* @param node A PropertyAssignment
*/
function substitutePropertyAssignment(node: PropertyAssignment): PropertyAssignment {
const literalName = isIdentifier(node.name) && trySubstituteReservedName(node.name);
if (literalName) {
return factory.updatePropertyAssignment(node, literalName, node.initializer);
}
return node;
}
/**
* If an identifier name is a reserved word, returns a string literal for the name.
*
* @param name An Identifier
*/
function trySubstituteReservedName(name: Identifier) {
const token = name.originalKeywordKind || (nodeIsSynthesized(name) ? stringToToken(idText(name)) : undefined);
if (token !== undefined && token >= SyntaxKind.FirstReservedWord && token <= SyntaxKind.LastReservedWord) {
return setTextRange(factory.createStringLiteralFromNode(name), name);
}
return undefined;
}
}
Computing file changes ...