package inliners import ( "strings" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/core" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/debug" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/jsnum" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/scanner" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers" ) type ConstEnumInliningTransformer struct { transformers.Transformer compilerOptions *core.CompilerOptions currentSourceFile *ast.SourceFile emitResolver printer.EmitResolver } func NewConstEnumInliningTransformer(opt *transformers.TransformOptions) *transformers.Transformer { compilerOptions := opt.CompilerOptions emitContext := opt.Context if compilerOptions.GetIsolatedModules() { debug.Fail("const enums are not inlined under isolated modules") } tx := &ConstEnumInliningTransformer{compilerOptions: compilerOptions, emitResolver: opt.EmitResolver} return tx.NewTransformer(tx.visit, emitContext) } func (tx *ConstEnumInliningTransformer) visit(node *ast.Node) *ast.Node { switch node.Kind { case ast.KindPropertyAccessExpression, ast.KindElementAccessExpression: { parse := tx.EmitContext().ParseNode(node) if parse == nil { return tx.Visitor().VisitEachChild(node) } value := tx.emitResolver.GetConstantValue(parse) if value != nil { var replacement *ast.Node switch v := value.(type) { case jsnum.Number: if v.IsInf() { if v.Abs() == v { replacement = tx.Factory().NewIdentifier("Infinity") } else { replacement = tx.Factory().NewPrefixUnaryExpression(ast.KindMinusToken, tx.Factory().NewIdentifier("Infinity")) } } else if v.IsNaN() { replacement = tx.Factory().NewIdentifier("NaN") } else if v.Abs() == v { replacement = tx.Factory().NewNumericLiteral(v.String()) } else { replacement = tx.Factory().NewPrefixUnaryExpression(ast.KindMinusToken, tx.Factory().NewNumericLiteral(v.Abs().String())) } case string: replacement = tx.Factory().NewStringLiteral(v) case jsnum.PseudoBigInt: // technically not supported by strada, and issues a checker error, handled here for completeness if v == (jsnum.PseudoBigInt{}) { replacement = tx.Factory().NewBigIntLiteral("0") } else if !v.Negative { replacement = tx.Factory().NewBigIntLiteral(v.Base10Value) } else { replacement = tx.Factory().NewPrefixUnaryExpression(ast.KindMinusToken, tx.Factory().NewBigIntLiteral(v.Base10Value)) } } if tx.compilerOptions.RemoveComments.IsFalseOrUnknown() { original := tx.EmitContext().MostOriginal(node) if original != nil && !ast.NodeIsSynthesized(original) { originalText := scanner.GetTextOfNode(original) escapedText := " " + safeMultiLineComment(originalText) + " " tx.EmitContext().AddSyntheticTrailingComment(replacement, ast.KindMultiLineCommentTrivia, escapedText, false) } } return replacement } return tx.Visitor().VisitEachChild(node) } } return tx.Visitor().VisitEachChild(node) } func safeMultiLineComment(text string) string { return strings.ReplaceAll(text, "*/", "*_/") }