remove unused packages
This commit is contained in:
parent
f1795ab4d0
commit
79197d8157
@ -1,54 +0,0 @@
|
||||
package transformers
|
||||
|
||||
import (
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/binder"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
|
||||
)
|
||||
|
||||
type chainedTransformer struct {
|
||||
Transformer
|
||||
components []*Transformer
|
||||
}
|
||||
|
||||
func (ch *chainedTransformer) visit(node *ast.Node) *ast.Node {
|
||||
if node.Kind != ast.KindSourceFile {
|
||||
panic("Chained transform passed non-sourcefile initial node")
|
||||
}
|
||||
result := node.AsSourceFile()
|
||||
for _, t := range ch.components {
|
||||
result = t.TransformSourceFile(result)
|
||||
}
|
||||
return result.AsNode()
|
||||
}
|
||||
|
||||
type TransformOptions struct {
|
||||
Context *printer.EmitContext
|
||||
CompilerOptions *core.CompilerOptions
|
||||
Resolver binder.ReferenceResolver
|
||||
EmitResolver printer.EmitResolver
|
||||
GetEmitModuleFormatOfFile func(file ast.HasFileName) core.ModuleKind
|
||||
}
|
||||
|
||||
type TransformerFactory = func(opt *TransformOptions) *Transformer
|
||||
|
||||
// Chains transforms in left-to-right order, running them one at a time in order (as opposed to interleaved at each node)
|
||||
// - the resulting combined transform only operates on SourceFile nodes
|
||||
func Chain(transforms ...TransformerFactory) TransformerFactory {
|
||||
if len(transforms) < 2 {
|
||||
if len(transforms) == 0 {
|
||||
panic("Expected some number of transforms to chain, but got none")
|
||||
}
|
||||
return transforms[0]
|
||||
}
|
||||
return func(opt *TransformOptions) *Transformer {
|
||||
constructed := make([]*Transformer, 0, len(transforms))
|
||||
for _, t := range transforms {
|
||||
// TODO: flatten nested chains?
|
||||
constructed = append(constructed, t(opt))
|
||||
}
|
||||
ch := &chainedTransformer{components: constructed}
|
||||
return ch.NewTransformer(ch.visit, opt.Context)
|
||||
}
|
||||
}
|
||||
@ -1,451 +0,0 @@
|
||||
package declarations
|
||||
|
||||
import (
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/diagnostics"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
|
||||
)
|
||||
|
||||
type GetSymbolAccessibilityDiagnostic = func(symbolAccessibilityResult printer.SymbolAccessibilityResult) *SymbolAccessibilityDiagnostic
|
||||
|
||||
type SymbolAccessibilityDiagnostic struct {
|
||||
errorNode *ast.Node
|
||||
diagnosticMessage *diagnostics.Message
|
||||
typeName *ast.Node
|
||||
}
|
||||
|
||||
func wrapSimpleDiagnosticSelector(node *ast.Node, selector func(node *ast.Node, symbolAccessibilityResult printer.SymbolAccessibilityResult) *diagnostics.Message) GetSymbolAccessibilityDiagnostic {
|
||||
return func(symbolAccessibilityResult printer.SymbolAccessibilityResult) *SymbolAccessibilityDiagnostic {
|
||||
diagnosticMessage := selector(node, symbolAccessibilityResult)
|
||||
if diagnosticMessage == nil {
|
||||
return nil
|
||||
}
|
||||
return &SymbolAccessibilityDiagnostic{
|
||||
errorNode: node,
|
||||
diagnosticMessage: diagnosticMessage,
|
||||
typeName: ast.GetNameOfDeclaration(node),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func wrapNamedDiagnosticSelector(node *ast.Node, selector func(node *ast.Node, symbolAccessibilityResult printer.SymbolAccessibilityResult) *diagnostics.Message) GetSymbolAccessibilityDiagnostic {
|
||||
return func(symbolAccessibilityResult printer.SymbolAccessibilityResult) *SymbolAccessibilityDiagnostic {
|
||||
diagnosticMessage := selector(node, symbolAccessibilityResult)
|
||||
if diagnosticMessage == nil {
|
||||
return nil
|
||||
}
|
||||
name := ast.GetNameOfDeclaration(node)
|
||||
return &SymbolAccessibilityDiagnostic{
|
||||
errorNode: name,
|
||||
diagnosticMessage: diagnosticMessage,
|
||||
typeName: name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func wrapFallbackErrorDiagnosticSelector(node *ast.Node, selector func(node *ast.Node, symbolAccessibilityResult printer.SymbolAccessibilityResult) *diagnostics.Message) GetSymbolAccessibilityDiagnostic {
|
||||
return func(symbolAccessibilityResult printer.SymbolAccessibilityResult) *SymbolAccessibilityDiagnostic {
|
||||
diagnosticMessage := selector(node, symbolAccessibilityResult)
|
||||
if diagnosticMessage == nil {
|
||||
return nil
|
||||
}
|
||||
errorNode := ast.GetNameOfDeclaration(node)
|
||||
if errorNode == nil {
|
||||
errorNode = node
|
||||
}
|
||||
return &SymbolAccessibilityDiagnostic{
|
||||
errorNode: errorNode,
|
||||
diagnosticMessage: diagnosticMessage,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func selectDiagnosticBasedOnModuleName(symbolAccessibilityResult printer.SymbolAccessibilityResult, moduleNotNameable *diagnostics.Message, privateModule *diagnostics.Message, nonModule *diagnostics.Message) *diagnostics.Message {
|
||||
if len(symbolAccessibilityResult.ErrorModuleName) > 0 {
|
||||
if symbolAccessibilityResult.Accessibility == printer.SymbolAccessibilityCannotBeNamed {
|
||||
return moduleNotNameable
|
||||
}
|
||||
return privateModule
|
||||
}
|
||||
return nonModule
|
||||
}
|
||||
|
||||
func selectDiagnosticBasedOnModuleNameNoNameCheck(symbolAccessibilityResult printer.SymbolAccessibilityResult, privateModule *diagnostics.Message, nonModule *diagnostics.Message) *diagnostics.Message {
|
||||
if len(symbolAccessibilityResult.ErrorModuleName) > 0 {
|
||||
return privateModule
|
||||
}
|
||||
return nonModule
|
||||
}
|
||||
|
||||
func createGetSymbolAccessibilityDiagnosticForNodeName(node *ast.Node) GetSymbolAccessibilityDiagnostic {
|
||||
if ast.IsSetAccessorDeclaration(node) || ast.IsGetAccessorDeclaration(node) {
|
||||
return wrapSimpleDiagnosticSelector(node, getAccessorNameVisibilityDiagnosticMessage)
|
||||
} else if ast.IsMethodDeclaration(node) || ast.IsMethodSignatureDeclaration(node) {
|
||||
return wrapSimpleDiagnosticSelector(node, getMethodNameVisibilityDiagnosticMessage)
|
||||
} else {
|
||||
return createGetSymbolAccessibilityDiagnosticForNode(node)
|
||||
}
|
||||
}
|
||||
|
||||
func getAccessorNameVisibilityDiagnosticMessage(node *ast.Node, symbolAccessibilityResult printer.SymbolAccessibilityResult) *diagnostics.Message {
|
||||
if ast.IsStatic(node) {
|
||||
return selectDiagnosticBasedOnModuleName(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named,
|
||||
diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2,
|
||||
diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_private_name_1,
|
||||
)
|
||||
} else if node.Parent.Kind == ast.KindClassDeclaration {
|
||||
return selectDiagnosticBasedOnModuleName(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named,
|
||||
diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2,
|
||||
diagnostics.Public_property_0_of_exported_class_has_or_is_using_private_name_1,
|
||||
)
|
||||
} else {
|
||||
return selectDiagnosticBasedOnModuleNameNoNameCheck(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Property_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2,
|
||||
diagnostics.Property_0_of_exported_interface_has_or_is_using_private_name_1,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func getMethodNameVisibilityDiagnosticMessage(node *ast.Node, symbolAccessibilityResult printer.SymbolAccessibilityResult) *diagnostics.Message {
|
||||
if ast.IsStatic(node) {
|
||||
return selectDiagnosticBasedOnModuleName(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Public_static_method_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named,
|
||||
diagnostics.Public_static_method_0_of_exported_class_has_or_is_using_name_1_from_private_module_2,
|
||||
diagnostics.Public_static_method_0_of_exported_class_has_or_is_using_private_name_1,
|
||||
)
|
||||
} else if node.Parent.Kind == ast.KindClassDeclaration {
|
||||
return selectDiagnosticBasedOnModuleName(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Public_method_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named,
|
||||
diagnostics.Public_method_0_of_exported_class_has_or_is_using_name_1_from_private_module_2,
|
||||
diagnostics.Public_method_0_of_exported_class_has_or_is_using_private_name_1,
|
||||
)
|
||||
} else {
|
||||
return selectDiagnosticBasedOnModuleNameNoNameCheck(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Method_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2,
|
||||
diagnostics.Method_0_of_exported_interface_has_or_is_using_private_name_1,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func createGetSymbolAccessibilityDiagnosticForNode(node *ast.Node) GetSymbolAccessibilityDiagnostic {
|
||||
if ast.IsVariableDeclaration(node) || ast.IsPropertyDeclaration(node) || ast.IsPropertySignatureDeclaration(node) || ast.IsPropertyAccessExpression(node) || ast.IsElementAccessExpression(node) || ast.IsBinaryExpression(node) || ast.IsBindingElement(node) || ast.IsConstructorDeclaration(node) {
|
||||
return wrapSimpleDiagnosticSelector(node, getVariableDeclarationTypeVisibilityDiagnosticMessage)
|
||||
} else if ast.IsSetAccessorDeclaration(node) || ast.IsGetAccessorDeclaration(node) {
|
||||
return wrapNamedDiagnosticSelector(node, getAccessorDeclarationTypeVisibilityDiagnosticMessage)
|
||||
} else if ast.IsConstructSignatureDeclaration(node) || ast.IsCallSignatureDeclaration(node) || ast.IsMethodDeclaration(node) || ast.IsMethodSignatureDeclaration(node) || ast.IsFunctionDeclaration(node) || ast.IsIndexSignatureDeclaration(node) {
|
||||
return wrapFallbackErrorDiagnosticSelector(node, getReturnTypeVisibilityDiagnosticMessage)
|
||||
} else if ast.IsParameter(node) {
|
||||
if ast.IsParameterPropertyDeclaration(node, node.Parent) && ast.HasSyntacticModifier(node.Parent, ast.ModifierFlagsPrivate) {
|
||||
return wrapSimpleDiagnosticSelector(node, getVariableDeclarationTypeVisibilityDiagnosticMessage)
|
||||
}
|
||||
return wrapSimpleDiagnosticSelector(node, getParameterDeclarationTypeVisibilityDiagnosticMessage)
|
||||
} else if ast.IsTypeParameterDeclaration(node) {
|
||||
return wrapSimpleDiagnosticSelector(node, getTypeParameterConstraintVisibilityDiagnosticMessage)
|
||||
} else if ast.IsExpressionWithTypeArguments(node) {
|
||||
// unique node selection behavior, inline closure
|
||||
return func(symbolAccessibilityResult printer.SymbolAccessibilityResult) *SymbolAccessibilityDiagnostic {
|
||||
var diagnosticMessage *diagnostics.Message
|
||||
// Heritage clause is written by user so it can always be named
|
||||
if ast.IsClassDeclaration(node.Parent.Parent) {
|
||||
// Class or Interface implemented/extended is inaccessible
|
||||
if ast.IsHeritageClause(node.Parent) && node.Parent.AsHeritageClause().Token == ast.KindImplementsKeyword {
|
||||
diagnosticMessage = diagnostics.Implements_clause_of_exported_class_0_has_or_is_using_private_name_1
|
||||
} else {
|
||||
if node.Parent.Parent.Name() != nil {
|
||||
diagnosticMessage = diagnostics.X_extends_clause_of_exported_class_0_has_or_is_using_private_name_1
|
||||
} else {
|
||||
diagnosticMessage = diagnostics.X_extends_clause_of_exported_class_has_or_is_using_private_name_0
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// interface is inaccessible
|
||||
diagnosticMessage = diagnostics.X_extends_clause_of_exported_interface_0_has_or_is_using_private_name_1
|
||||
}
|
||||
|
||||
return &SymbolAccessibilityDiagnostic{
|
||||
diagnosticMessage: diagnosticMessage,
|
||||
errorNode: node,
|
||||
typeName: ast.GetNameOfDeclaration(node.Parent.Parent),
|
||||
}
|
||||
}
|
||||
} else if ast.IsImportEqualsDeclaration(node) {
|
||||
return wrapSimpleDiagnosticSelector(node, func(_ *ast.Node, _ printer.SymbolAccessibilityResult) *diagnostics.Message {
|
||||
return diagnostics.Import_declaration_0_is_using_private_name_1
|
||||
})
|
||||
} else if ast.IsTypeAliasDeclaration(node) || ast.IsJSTypeAliasDeclaration(node) {
|
||||
// unique node selection behavior, inline closure
|
||||
return func(symbolAccessibilityResult printer.SymbolAccessibilityResult) *SymbolAccessibilityDiagnostic {
|
||||
diagnosticMessage := selectDiagnosticBasedOnModuleNameNoNameCheck(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Exported_type_alias_0_has_or_is_using_private_name_1_from_module_2,
|
||||
diagnostics.Exported_type_alias_0_has_or_is_using_private_name_1,
|
||||
)
|
||||
errorNode := node.AsTypeAliasDeclaration().Type
|
||||
typeName := node.Name()
|
||||
return &SymbolAccessibilityDiagnostic{
|
||||
errorNode: errorNode,
|
||||
diagnosticMessage: diagnosticMessage,
|
||||
typeName: typeName,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panic("Attempted to set a declaration diagnostic context for unhandled node kind: " + node.Kind.String())
|
||||
}
|
||||
}
|
||||
|
||||
func getVariableDeclarationTypeVisibilityDiagnosticMessage(node *ast.Node, symbolAccessibilityResult printer.SymbolAccessibilityResult) *diagnostics.Message {
|
||||
if node.Kind == ast.KindVariableDeclaration || node.Kind == ast.KindBindingElement {
|
||||
return selectDiagnosticBasedOnModuleName(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Exported_variable_0_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named,
|
||||
diagnostics.Exported_variable_0_has_or_is_using_name_1_from_private_module_2,
|
||||
diagnostics.Exported_variable_0_has_or_is_using_private_name_1,
|
||||
)
|
||||
|
||||
// This check is to ensure we don't report error on constructor parameter property as that error would be reported during parameter emit
|
||||
// The only exception here is if the constructor was marked as private. we are not emitting the constructor parameters at all.
|
||||
} else if node.Kind == ast.KindPropertyDeclaration || node.Kind == ast.KindPropertyAccessExpression || node.Kind == ast.KindElementAccessExpression || node.Kind == ast.KindBinaryExpression || node.Kind == ast.KindPropertySignature ||
|
||||
(node.Kind == ast.KindParameter && ast.HasSyntacticModifier(node.Parent, ast.ModifierFlagsPrivate)) {
|
||||
// TODO(jfreeman): Deal with computed properties in error reporting.
|
||||
if ast.IsStatic(node) {
|
||||
return selectDiagnosticBasedOnModuleName(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named,
|
||||
diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2,
|
||||
diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_private_name_1,
|
||||
)
|
||||
} else if node.Parent.Kind == ast.KindClassDeclaration || node.Kind == ast.KindParameter {
|
||||
return selectDiagnosticBasedOnModuleName(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named,
|
||||
diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2,
|
||||
diagnostics.Public_property_0_of_exported_class_has_or_is_using_private_name_1,
|
||||
)
|
||||
} else {
|
||||
// Interfaces cannot have types that cannot be named
|
||||
return selectDiagnosticBasedOnModuleNameNoNameCheck(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Property_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2,
|
||||
diagnostics.Property_0_of_exported_interface_has_or_is_using_private_name_1,
|
||||
)
|
||||
}
|
||||
}
|
||||
return nil // TODO: Audit behavior - should this panic? potentially silent error state in strada
|
||||
}
|
||||
|
||||
func getAccessorDeclarationTypeVisibilityDiagnosticMessage(node *ast.Node, symbolAccessibilityResult printer.SymbolAccessibilityResult) *diagnostics.Message {
|
||||
if node.Kind == ast.KindSetAccessor {
|
||||
// Getters can infer the return type from the returned expression, but setters cannot, so the
|
||||
// "_from_external_module_1_but_cannot_be_named" case cannot occur.
|
||||
if ast.IsStatic(node) {
|
||||
return selectDiagnosticBasedOnModuleNameNoNameCheck(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Parameter_type_of_public_static_setter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2,
|
||||
diagnostics.Parameter_type_of_public_static_setter_0_from_exported_class_has_or_is_using_private_name_1,
|
||||
)
|
||||
} else {
|
||||
return selectDiagnosticBasedOnModuleNameNoNameCheck(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Parameter_type_of_public_setter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2,
|
||||
diagnostics.Parameter_type_of_public_setter_0_from_exported_class_has_or_is_using_private_name_1,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if ast.IsStatic(node) {
|
||||
return selectDiagnosticBasedOnModuleName(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Return_type_of_public_static_getter_0_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named,
|
||||
diagnostics.Return_type_of_public_static_getter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2,
|
||||
diagnostics.Return_type_of_public_static_getter_0_from_exported_class_has_or_is_using_private_name_1,
|
||||
)
|
||||
} else {
|
||||
return selectDiagnosticBasedOnModuleName(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Return_type_of_public_getter_0_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named,
|
||||
diagnostics.Return_type_of_public_getter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2,
|
||||
diagnostics.Return_type_of_public_getter_0_from_exported_class_has_or_is_using_private_name_1,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getReturnTypeVisibilityDiagnosticMessage(node *ast.Node, symbolAccessibilityResult printer.SymbolAccessibilityResult) *diagnostics.Message {
|
||||
switch node.Kind {
|
||||
case ast.KindConstructSignature:
|
||||
// Interfaces cannot have return types that cannot be named
|
||||
return selectDiagnosticBasedOnModuleNameNoNameCheck(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1,
|
||||
diagnostics.Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_0,
|
||||
)
|
||||
case ast.KindCallSignature:
|
||||
// Interfaces cannot have return types that cannot be named
|
||||
return selectDiagnosticBasedOnModuleNameNoNameCheck(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Return_type_of_call_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1,
|
||||
diagnostics.Return_type_of_call_signature_from_exported_interface_has_or_is_using_private_name_0,
|
||||
)
|
||||
case ast.KindIndexSignature:
|
||||
// Interfaces cannot have return types that cannot be named
|
||||
return selectDiagnosticBasedOnModuleNameNoNameCheck(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Return_type_of_index_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1,
|
||||
diagnostics.Return_type_of_index_signature_from_exported_interface_has_or_is_using_private_name_0,
|
||||
)
|
||||
|
||||
case ast.KindMethodDeclaration, ast.KindMethodSignature:
|
||||
if ast.IsStatic(node) {
|
||||
return selectDiagnosticBasedOnModuleName(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named,
|
||||
diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_private_module_1,
|
||||
diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_private_name_0,
|
||||
)
|
||||
} else if node.Parent.Kind == ast.KindClassDeclaration {
|
||||
return selectDiagnosticBasedOnModuleName(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named,
|
||||
diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_private_module_1,
|
||||
diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_private_name_0,
|
||||
)
|
||||
} else {
|
||||
// Interfaces cannot have return types that cannot be named
|
||||
return selectDiagnosticBasedOnModuleNameNoNameCheck(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Return_type_of_method_from_exported_interface_has_or_is_using_name_0_from_private_module_1,
|
||||
diagnostics.Return_type_of_method_from_exported_interface_has_or_is_using_private_name_0,
|
||||
)
|
||||
}
|
||||
case ast.KindFunctionDeclaration:
|
||||
return selectDiagnosticBasedOnModuleName(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Return_type_of_exported_function_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named,
|
||||
diagnostics.Return_type_of_exported_function_has_or_is_using_name_0_from_private_module_1,
|
||||
diagnostics.Return_type_of_exported_function_has_or_is_using_private_name_0,
|
||||
)
|
||||
default:
|
||||
panic("This is unknown kind for signature: " + node.Kind.String())
|
||||
}
|
||||
}
|
||||
|
||||
func getParameterDeclarationTypeVisibilityDiagnosticMessage(node *ast.Node, symbolAccessibilityResult printer.SymbolAccessibilityResult) *diagnostics.Message {
|
||||
switch node.Parent.Kind {
|
||||
case ast.KindConstructor:
|
||||
return selectDiagnosticBasedOnModuleName(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named,
|
||||
diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_private_module_2,
|
||||
diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_private_name_1,
|
||||
)
|
||||
|
||||
case ast.KindConstructSignature, ast.KindConstructorType:
|
||||
// Interfaces cannot have parameter types that cannot be named
|
||||
return selectDiagnosticBasedOnModuleNameNoNameCheck(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2,
|
||||
diagnostics.Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1,
|
||||
)
|
||||
|
||||
case ast.KindCallSignature:
|
||||
// Interfaces cannot have parameter types that cannot be named
|
||||
return selectDiagnosticBasedOnModuleNameNoNameCheck(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2,
|
||||
diagnostics.Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1,
|
||||
)
|
||||
|
||||
case ast.KindIndexSignature:
|
||||
// Interfaces cannot have parameter types that cannot be named
|
||||
return selectDiagnosticBasedOnModuleNameNoNameCheck(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Parameter_0_of_index_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2,
|
||||
diagnostics.Parameter_0_of_index_signature_from_exported_interface_has_or_is_using_private_name_1,
|
||||
)
|
||||
|
||||
case ast.KindMethodDeclaration, ast.KindMethodSignature:
|
||||
if ast.IsStatic(node.Parent) {
|
||||
return selectDiagnosticBasedOnModuleName(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named,
|
||||
diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_private_module_2,
|
||||
diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1,
|
||||
)
|
||||
} else if node.Parent.Parent.Kind == ast.KindClassDeclaration {
|
||||
return selectDiagnosticBasedOnModuleName(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named,
|
||||
diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_private_module_2,
|
||||
diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1,
|
||||
)
|
||||
} else {
|
||||
// Interfaces cannot have parameter types that cannot be named
|
||||
return selectDiagnosticBasedOnModuleNameNoNameCheck(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Parameter_0_of_method_from_exported_interface_has_or_is_using_name_1_from_private_module_2,
|
||||
diagnostics.Parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1,
|
||||
)
|
||||
}
|
||||
|
||||
case ast.KindFunctionDeclaration, ast.KindFunctionType:
|
||||
return selectDiagnosticBasedOnModuleName(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Parameter_0_of_exported_function_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named,
|
||||
diagnostics.Parameter_0_of_exported_function_has_or_is_using_name_1_from_private_module_2,
|
||||
diagnostics.Parameter_0_of_exported_function_has_or_is_using_private_name_1,
|
||||
)
|
||||
case ast.KindSetAccessor, ast.KindGetAccessor:
|
||||
return selectDiagnosticBasedOnModuleName(
|
||||
symbolAccessibilityResult,
|
||||
diagnostics.Parameter_0_of_accessor_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named,
|
||||
diagnostics.Parameter_0_of_accessor_has_or_is_using_name_1_from_private_module_2,
|
||||
diagnostics.Parameter_0_of_accessor_has_or_is_using_private_name_1,
|
||||
)
|
||||
default:
|
||||
panic("Unknown parent for parameter: " + node.Parent.Kind.String())
|
||||
}
|
||||
}
|
||||
|
||||
func getTypeParameterConstraintVisibilityDiagnosticMessage(node *ast.Node, symbolAccessibilityResult printer.SymbolAccessibilityResult) *diagnostics.Message {
|
||||
// Type parameter constraints are named by user so we should always be able to name it
|
||||
switch node.Parent.Kind {
|
||||
case ast.KindClassDeclaration:
|
||||
return diagnostics.Type_parameter_0_of_exported_class_has_or_is_using_private_name_1
|
||||
case ast.KindInterfaceDeclaration:
|
||||
return diagnostics.Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1
|
||||
case ast.KindMappedType:
|
||||
return diagnostics.Type_parameter_0_of_exported_mapped_object_type_is_using_private_name_1
|
||||
case ast.KindConstructorType, ast.KindConstructSignature:
|
||||
return diagnostics.Type_parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1
|
||||
case ast.KindCallSignature:
|
||||
return diagnostics.Type_parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1
|
||||
case ast.KindMethodDeclaration, ast.KindMethodSignature:
|
||||
if ast.IsStatic(node.Parent) {
|
||||
return diagnostics.Type_parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1
|
||||
} else if node.Parent.Parent.Kind == ast.KindClassDeclaration {
|
||||
return diagnostics.Type_parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1
|
||||
} else {
|
||||
return diagnostics.Type_parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1
|
||||
}
|
||||
case ast.KindFunctionType, ast.KindFunctionDeclaration:
|
||||
return diagnostics.Type_parameter_0_of_exported_function_has_or_is_using_private_name_1
|
||||
|
||||
case ast.KindInferType:
|
||||
return diagnostics.Extends_clause_for_inferred_type_0_has_or_is_using_private_name_1
|
||||
|
||||
case ast.KindTypeAliasDeclaration, ast.KindJSTypeAliasDeclaration:
|
||||
return diagnostics.Type_parameter_0_of_exported_type_alias_has_or_is_using_private_name_1
|
||||
|
||||
default:
|
||||
panic("This is unknown parent for type parameter: " + node.Parent.Kind.String())
|
||||
}
|
||||
}
|
||||
|
||||
// !!! TODO isolatedDeclarations createGetIsolatedDeclarationErrors
|
||||
@ -1,219 +0,0 @@
|
||||
package declarations
|
||||
|
||||
import (
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/checker"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/diagnostics"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/modulespecifiers"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/scanner"
|
||||
)
|
||||
|
||||
type SymbolTrackerImpl struct {
|
||||
resolver printer.EmitResolver
|
||||
state *SymbolTrackerSharedState
|
||||
host DeclarationEmitHost
|
||||
fallbackStack []*ast.Node
|
||||
}
|
||||
|
||||
// GetModuleSpecifierGenerationHost implements checker.SymbolTracker.
|
||||
func (s *SymbolTrackerImpl) GetModuleSpecifierGenerationHost() modulespecifiers.ModuleSpecifierGenerationHost {
|
||||
return s.host
|
||||
}
|
||||
|
||||
// PopErrorFallbackNode implements checker.SymbolTracker.
|
||||
func (s *SymbolTrackerImpl) PopErrorFallbackNode() {
|
||||
s.fallbackStack = s.fallbackStack[:len(s.fallbackStack)-1]
|
||||
}
|
||||
|
||||
// PushErrorFallbackNode implements checker.SymbolTracker.
|
||||
func (s *SymbolTrackerImpl) PushErrorFallbackNode(node *ast.Node) {
|
||||
s.fallbackStack = append(s.fallbackStack, node)
|
||||
}
|
||||
|
||||
// ReportCyclicStructureError implements checker.SymbolTracker.
|
||||
func (s *SymbolTrackerImpl) ReportCyclicStructureError() {
|
||||
location := s.errorLocation()
|
||||
if location != nil {
|
||||
s.state.addDiagnostic(createDiagnosticForNode(location, diagnostics.The_inferred_type_of_0_references_a_type_with_a_cyclic_structure_which_cannot_be_trivially_serialized_A_type_annotation_is_necessary, s.errorDeclarationNameWithFallback()))
|
||||
}
|
||||
}
|
||||
|
||||
// ReportInaccessibleThisError implements checker.SymbolTracker.
|
||||
func (s *SymbolTrackerImpl) ReportInaccessibleThisError() {
|
||||
location := s.errorLocation()
|
||||
if location != nil {
|
||||
s.state.addDiagnostic(createDiagnosticForNode(location, diagnostics.The_inferred_type_of_0_references_an_inaccessible_1_type_A_type_annotation_is_necessary, s.errorDeclarationNameWithFallback(), "this"))
|
||||
}
|
||||
}
|
||||
|
||||
// ReportInaccessibleUniqueSymbolError implements checker.SymbolTracker.
|
||||
func (s *SymbolTrackerImpl) ReportInaccessibleUniqueSymbolError() {
|
||||
location := s.errorLocation()
|
||||
if location != nil {
|
||||
s.state.addDiagnostic(createDiagnosticForNode(location, diagnostics.The_inferred_type_of_0_references_an_inaccessible_1_type_A_type_annotation_is_necessary, s.errorDeclarationNameWithFallback(), "unique symbol"))
|
||||
}
|
||||
}
|
||||
|
||||
// ReportInferenceFallback implements checker.SymbolTracker.
|
||||
func (s *SymbolTrackerImpl) ReportInferenceFallback(node *ast.Node) {
|
||||
if s.state.isolatedDeclarations || ast.IsSourceFileJS(s.state.currentSourceFile) {
|
||||
return
|
||||
}
|
||||
if ast.GetSourceFileOfNode(node) != s.state.currentSourceFile {
|
||||
return // Nested error on a declaration in another file - ignore, will be reemitted if file is in the output file set
|
||||
}
|
||||
if ast.IsVariableDeclaration(node) && s.state.resolver.IsExpandoFunctionDeclaration(node) {
|
||||
s.state.reportExpandoFunctionErrors(node)
|
||||
} else {
|
||||
// !!! isolatedDeclaration support
|
||||
// s.state.addDiagnostic(getIsolatedDeclarationError(node))
|
||||
}
|
||||
}
|
||||
|
||||
// ReportLikelyUnsafeImportRequiredError implements checker.SymbolTracker.
|
||||
func (s *SymbolTrackerImpl) ReportLikelyUnsafeImportRequiredError(specifier string) {
|
||||
location := s.errorLocation()
|
||||
if location != nil {
|
||||
s.state.addDiagnostic(createDiagnosticForNode(location, diagnostics.The_inferred_type_of_0_cannot_be_named_without_a_reference_to_1_This_is_likely_not_portable_A_type_annotation_is_necessary, s.errorDeclarationNameWithFallback(), specifier))
|
||||
}
|
||||
}
|
||||
|
||||
// ReportNonSerializableProperty implements checker.SymbolTracker.
|
||||
func (s *SymbolTrackerImpl) ReportNonSerializableProperty(propertyName string) {
|
||||
location := s.errorLocation()
|
||||
if location != nil {
|
||||
s.state.addDiagnostic(createDiagnosticForNode(location, diagnostics.The_type_of_this_node_cannot_be_serialized_because_its_property_0_cannot_be_serialized, propertyName))
|
||||
}
|
||||
}
|
||||
|
||||
// ReportNonlocalAugmentation implements checker.SymbolTracker.
|
||||
func (s *SymbolTrackerImpl) ReportNonlocalAugmentation(containingFile *ast.SourceFile, parentSymbol *ast.Symbol, augmentingSymbol *ast.Symbol) {
|
||||
primaryDeclaration := core.Find(parentSymbol.Declarations, func(d *ast.Node) bool { return ast.GetSourceFileOfNode(d) == containingFile })
|
||||
augmentingDeclarations := core.Filter(augmentingSymbol.Declarations, func(d *ast.Node) bool { return ast.GetSourceFileOfNode(d) != containingFile })
|
||||
if primaryDeclaration != nil && len(augmentingDeclarations) > 0 {
|
||||
for _, augmentations := range augmentingDeclarations {
|
||||
diag := createDiagnosticForNode(augmentations, diagnostics.Declaration_augments_declaration_in_another_file_This_cannot_be_serialized)
|
||||
related := createDiagnosticForNode(primaryDeclaration, diagnostics.This_is_the_declaration_being_augmented_Consider_moving_the_augmenting_declaration_into_the_same_file)
|
||||
diag.AddRelatedInfo(related)
|
||||
s.state.addDiagnostic(diag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ReportPrivateInBaseOfClassExpression implements checker.SymbolTracker.
|
||||
func (s *SymbolTrackerImpl) ReportPrivateInBaseOfClassExpression(propertyName string) {
|
||||
location := s.errorLocation()
|
||||
if location != nil {
|
||||
diag := createDiagnosticForNode(location, diagnostics.Property_0_of_exported_anonymous_class_type_may_not_be_private_or_protected, propertyName)
|
||||
if ast.IsVariableDeclaration(location.Parent) {
|
||||
related := createDiagnosticForNode(location, diagnostics.Add_a_type_annotation_to_the_variable_0, s.errorDeclarationNameWithFallback())
|
||||
diag.AddRelatedInfo(related)
|
||||
}
|
||||
s.state.addDiagnostic(diag)
|
||||
}
|
||||
}
|
||||
|
||||
// ReportTruncationError implements checker.SymbolTracker.
|
||||
func (s *SymbolTrackerImpl) ReportTruncationError() {
|
||||
location := s.errorLocation()
|
||||
if location != nil {
|
||||
s.state.addDiagnostic(createDiagnosticForNode(location, diagnostics.The_inferred_type_of_this_node_exceeds_the_maximum_length_the_compiler_will_serialize_An_explicit_type_annotation_is_needed))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SymbolTrackerImpl) errorFallbackNode() *ast.Node {
|
||||
if len(s.fallbackStack) >= 1 {
|
||||
return s.fallbackStack[len(s.fallbackStack)-1]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SymbolTrackerImpl) errorLocation() *ast.Node {
|
||||
location := s.state.errorNameNode
|
||||
if location == nil {
|
||||
location = s.errorFallbackNode()
|
||||
}
|
||||
return location
|
||||
}
|
||||
|
||||
func (s *SymbolTrackerImpl) errorDeclarationNameWithFallback() string {
|
||||
if s.state.errorNameNode != nil {
|
||||
return scanner.DeclarationNameToString(s.state.errorNameNode)
|
||||
}
|
||||
if s.errorFallbackNode() != nil && ast.GetNameOfDeclaration(s.errorFallbackNode()) != nil {
|
||||
return scanner.DeclarationNameToString(ast.GetNameOfDeclaration(s.errorFallbackNode()))
|
||||
}
|
||||
if s.errorFallbackNode() != nil && ast.IsExportAssignment(s.errorFallbackNode()) {
|
||||
if s.errorFallbackNode().AsExportAssignment().IsExportEquals {
|
||||
return "export="
|
||||
}
|
||||
return "default"
|
||||
}
|
||||
return "(Missing)" // same fallback declarationNameToString uses when node is zero-width (ie, nameless)
|
||||
}
|
||||
|
||||
// TrackSymbol implements checker.SymbolTracker.
|
||||
func (s *SymbolTrackerImpl) TrackSymbol(symbol *ast.Symbol, enclosingDeclaration *ast.Node, meaning ast.SymbolFlags) bool {
|
||||
if symbol.Flags&ast.SymbolFlagsTypeParameter != 0 {
|
||||
return false
|
||||
}
|
||||
issuedDiagnostic := s.handleSymbolAccessibilityError(s.resolver.IsSymbolAccessible(symbol, enclosingDeclaration, meaning /*shouldComputeAliasToMarkVisible*/, true))
|
||||
return issuedDiagnostic
|
||||
}
|
||||
|
||||
func (s *SymbolTrackerImpl) handleSymbolAccessibilityError(symbolAccessibilityResult printer.SymbolAccessibilityResult) bool {
|
||||
if symbolAccessibilityResult.Accessibility == printer.SymbolAccessibilityAccessible {
|
||||
// Add aliases back onto the possible imports list if they're not there so we can try them again with updated visibility info
|
||||
if len(symbolAccessibilityResult.AliasesToMakeVisible) > 0 {
|
||||
for _, ref := range symbolAccessibilityResult.AliasesToMakeVisible {
|
||||
s.state.lateMarkedStatements = core.AppendIfUnique(s.state.lateMarkedStatements, ref)
|
||||
}
|
||||
}
|
||||
// TODO: Do all these accessibility checks inside/after the first pass in the checker when declarations are enabled, if possible
|
||||
|
||||
// The checker should issue errors on unresolvable names, skip the declaration emit error for using a private/unreachable name for those
|
||||
} else if symbolAccessibilityResult.Accessibility != printer.SymbolAccessibilityNotResolved {
|
||||
// Report error
|
||||
errorInfo := s.state.getSymbolAccessibilityDiagnostic(symbolAccessibilityResult)
|
||||
if errorInfo != nil {
|
||||
info := *errorInfo
|
||||
diagNode := symbolAccessibilityResult.ErrorNode
|
||||
if diagNode == nil {
|
||||
diagNode = errorInfo.errorNode
|
||||
}
|
||||
if info.typeName != nil {
|
||||
s.state.addDiagnostic(createDiagnosticForNode(diagNode, info.diagnosticMessage, scanner.GetTextOfNode(info.typeName), symbolAccessibilityResult.ErrorSymbolName, symbolAccessibilityResult.ErrorModuleName))
|
||||
} else {
|
||||
s.state.addDiagnostic(createDiagnosticForNode(diagNode, info.diagnosticMessage, symbolAccessibilityResult.ErrorSymbolName, symbolAccessibilityResult.ErrorModuleName))
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func createDiagnosticForNode(node *ast.Node, message *diagnostics.Message, args ...any) *ast.Diagnostic {
|
||||
return checker.NewDiagnosticForNode(node, message, args...)
|
||||
}
|
||||
|
||||
type SymbolTrackerSharedState struct {
|
||||
lateMarkedStatements []*ast.Node
|
||||
diagnostics []*ast.Diagnostic
|
||||
getSymbolAccessibilityDiagnostic GetSymbolAccessibilityDiagnostic
|
||||
errorNameNode *ast.Node
|
||||
isolatedDeclarations bool
|
||||
currentSourceFile *ast.SourceFile
|
||||
resolver printer.EmitResolver
|
||||
reportExpandoFunctionErrors func(node *ast.Node)
|
||||
}
|
||||
|
||||
func (s *SymbolTrackerSharedState) addDiagnostic(diag *ast.Diagnostic) {
|
||||
s.diagnostics = append(s.diagnostics, diag)
|
||||
}
|
||||
|
||||
func NewSymbolTracker(host DeclarationEmitHost, resolver printer.EmitResolver, state *SymbolTrackerSharedState) *SymbolTrackerImpl {
|
||||
tracker := &SymbolTrackerImpl{host: host, resolver: resolver, state: state}
|
||||
return tracker
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,236 +0,0 @@
|
||||
package declarations
|
||||
|
||||
import (
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
|
||||
)
|
||||
|
||||
func needsScopeMarker(result *ast.Node) bool {
|
||||
return !ast.IsAnyImportOrReExport(result) && !ast.IsExportAssignment(result) && !ast.HasSyntacticModifier(result, ast.ModifierFlagsExport) && !ast.IsAmbientModule(result)
|
||||
}
|
||||
|
||||
func canHaveLiteralInitializer(host DeclarationEmitHost, node *ast.Node) bool {
|
||||
switch node.Kind {
|
||||
case ast.KindPropertyDeclaration,
|
||||
ast.KindPropertySignature:
|
||||
return host.GetEffectiveDeclarationFlags(node, ast.ModifierFlagsPrivate) != 0
|
||||
case ast.KindParameter,
|
||||
ast.KindVariableDeclaration:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func canProduceDiagnostics(node *ast.Node) bool {
|
||||
return ast.IsVariableDeclaration(node) ||
|
||||
ast.IsPropertyDeclaration(node) ||
|
||||
ast.IsPropertySignatureDeclaration(node) ||
|
||||
ast.IsBindingElement(node) ||
|
||||
ast.IsSetAccessorDeclaration(node) ||
|
||||
ast.IsGetAccessorDeclaration(node) ||
|
||||
ast.IsConstructSignatureDeclaration(node) ||
|
||||
ast.IsCallSignatureDeclaration(node) ||
|
||||
ast.IsMethodDeclaration(node) ||
|
||||
ast.IsMethodSignatureDeclaration(node) ||
|
||||
ast.IsFunctionDeclaration(node) ||
|
||||
ast.IsParameter(node) ||
|
||||
ast.IsTypeParameterDeclaration(node) ||
|
||||
ast.IsExpressionWithTypeArguments(node) ||
|
||||
ast.IsImportEqualsDeclaration(node) ||
|
||||
ast.IsTypeAliasDeclaration(node) ||
|
||||
ast.IsJSTypeAliasDeclaration(node) ||
|
||||
ast.IsConstructorDeclaration(node) ||
|
||||
ast.IsIndexSignatureDeclaration(node) ||
|
||||
ast.IsPropertyAccessExpression(node) ||
|
||||
ast.IsElementAccessExpression(node) ||
|
||||
ast.IsBinaryExpression(node) // || // !!! TODO: JSDoc support
|
||||
/* ast.IsJSDocTypeAlias(node); */
|
||||
}
|
||||
|
||||
func hasInferredType(node *ast.Node) bool {
|
||||
// Debug.type<HasInferredType>(node); // !!!
|
||||
switch node.Kind {
|
||||
case ast.KindParameter,
|
||||
ast.KindPropertySignature,
|
||||
ast.KindPropertyDeclaration,
|
||||
ast.KindBindingElement,
|
||||
ast.KindPropertyAccessExpression,
|
||||
ast.KindElementAccessExpression,
|
||||
ast.KindBinaryExpression,
|
||||
ast.KindVariableDeclaration,
|
||||
ast.KindExportAssignment,
|
||||
ast.KindJSExportAssignment,
|
||||
ast.KindPropertyAssignment,
|
||||
ast.KindShorthandPropertyAssignment,
|
||||
ast.KindJSDocParameterTag,
|
||||
ast.KindJSDocPropertyTag:
|
||||
return true
|
||||
default:
|
||||
// assertType<never>(node); // !!!
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func isDeclarationAndNotVisible(emitContext *printer.EmitContext, resolver printer.EmitResolver, node *ast.Node) bool {
|
||||
node = emitContext.ParseNode(node)
|
||||
switch node.Kind {
|
||||
case ast.KindFunctionDeclaration,
|
||||
ast.KindModuleDeclaration,
|
||||
ast.KindInterfaceDeclaration,
|
||||
ast.KindClassDeclaration,
|
||||
ast.KindTypeAliasDeclaration,
|
||||
ast.KindJSTypeAliasDeclaration,
|
||||
ast.KindEnumDeclaration:
|
||||
return !resolver.IsDeclarationVisible(node)
|
||||
// The following should be doing their own visibility checks based on filtering their members
|
||||
case ast.KindVariableDeclaration:
|
||||
return !getBindingNameVisible(resolver, node)
|
||||
case ast.KindImportEqualsDeclaration,
|
||||
ast.KindImportDeclaration,
|
||||
ast.KindJSImportDeclaration,
|
||||
ast.KindExportDeclaration,
|
||||
ast.KindJSExportAssignment,
|
||||
ast.KindExportAssignment:
|
||||
return false
|
||||
case ast.KindClassStaticBlockDeclaration:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func getBindingNameVisible(resolver printer.EmitResolver, elem *ast.Node) bool {
|
||||
if ast.IsOmittedExpression(elem) {
|
||||
return false
|
||||
}
|
||||
// TODO: parseArrayBindingElement _never_ parses out an OmittedExpression anymore, instead producing a nameless binding element
|
||||
// Audit if OmittedExpression should be removed
|
||||
if elem.Name() == nil {
|
||||
return false
|
||||
}
|
||||
if ast.IsBindingPattern(elem.Name()) {
|
||||
// If any child binding pattern element has been marked visible (usually by collect linked aliases), then this is visible
|
||||
for _, elem := range elem.Name().AsBindingPattern().Elements.Nodes {
|
||||
if getBindingNameVisible(resolver, elem) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
} else {
|
||||
return resolver.IsDeclarationVisible(elem)
|
||||
}
|
||||
}
|
||||
|
||||
func isEnclosingDeclaration(node *ast.Node) bool {
|
||||
return ast.IsSourceFile(node) ||
|
||||
ast.IsTypeAliasDeclaration(node) ||
|
||||
ast.IsJSTypeAliasDeclaration(node) ||
|
||||
ast.IsModuleDeclaration(node) ||
|
||||
ast.IsClassDeclaration(node) ||
|
||||
ast.IsInterfaceDeclaration(node) ||
|
||||
ast.IsFunctionLike(node) ||
|
||||
ast.IsIndexSignatureDeclaration(node) ||
|
||||
ast.IsMappedTypeNode(node)
|
||||
}
|
||||
|
||||
func isAlwaysType(node *ast.Node) bool {
|
||||
if node.Kind == ast.KindInterfaceDeclaration {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func maskModifierFlags(host DeclarationEmitHost, node *ast.Node, modifierMask ast.ModifierFlags, modifierAdditions ast.ModifierFlags) ast.ModifierFlags {
|
||||
flags := host.GetEffectiveDeclarationFlags(node, modifierMask) | modifierAdditions
|
||||
if flags&ast.ModifierFlagsDefault != 0 && (flags&ast.ModifierFlagsExport == 0) {
|
||||
// A non-exported default is a nonsequitor - we usually try to remove all export modifiers
|
||||
// from statements in ambient declarations; but a default export must retain its export modifier to be syntactically valid
|
||||
flags ^= ast.ModifierFlagsExport
|
||||
}
|
||||
if flags&ast.ModifierFlagsDefault != 0 && flags&ast.ModifierFlagsAmbient != 0 {
|
||||
flags ^= ast.ModifierFlagsAmbient // `declare` is never required alongside `default` (and would be an error if printed)
|
||||
}
|
||||
return flags
|
||||
}
|
||||
|
||||
func unwrapParenthesizedExpression(o *ast.Node) *ast.Node {
|
||||
for o.Kind == ast.KindParenthesizedExpression {
|
||||
o = o.Expression()
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
func isPrimitiveLiteralValue(node *ast.Node, includeBigInt bool) bool {
|
||||
// !!! Debug.type<PrimitiveLiteral>(node);
|
||||
switch node.Kind {
|
||||
case ast.KindTrueKeyword,
|
||||
ast.KindFalseKeyword,
|
||||
ast.KindNumericLiteral,
|
||||
ast.KindStringLiteral,
|
||||
ast.KindNoSubstitutionTemplateLiteral:
|
||||
return true
|
||||
case ast.KindBigIntLiteral:
|
||||
return includeBigInt
|
||||
case ast.KindPrefixUnaryExpression:
|
||||
if node.AsPrefixUnaryExpression().Operator == ast.KindMinusToken {
|
||||
return ast.IsNumericLiteral(node.AsPrefixUnaryExpression().Operand) || (includeBigInt && ast.IsBigIntLiteral(node.AsPrefixUnaryExpression().Operand))
|
||||
}
|
||||
if node.AsPrefixUnaryExpression().Operator == ast.KindPlusToken {
|
||||
return ast.IsNumericLiteral(node.AsPrefixUnaryExpression().Operand)
|
||||
}
|
||||
return false
|
||||
default:
|
||||
// !!! assertType<never>(node);
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func isPrivateMethodTypeParameter(host DeclarationEmitHost, node *ast.TypeParameterDeclaration) bool {
|
||||
return node.AsNode().Parent.Kind == ast.KindMethodDeclaration && host.GetEffectiveDeclarationFlags(node.AsNode().Parent, ast.ModifierFlagsPrivate) != 0
|
||||
}
|
||||
|
||||
// If the ExpandoFunctionDeclaration have multiple overloads, then we only need to emit properties for the last one.
|
||||
func shouldEmitFunctionProperties(input *ast.FunctionDeclaration) bool {
|
||||
if input.Body != nil { // if it has an implementation, it must be the last one
|
||||
return true
|
||||
}
|
||||
|
||||
overloadSignatures := core.Filter(input.Symbol.Declarations, func(decl *ast.Node) bool {
|
||||
return ast.IsFunctionDeclaration(decl)
|
||||
})
|
||||
|
||||
return len(overloadSignatures) == 0 || overloadSignatures[len(overloadSignatures)-1] == input.AsNode()
|
||||
}
|
||||
|
||||
func getFirstConstructorWithBody(node *ast.Node) *ast.Node {
|
||||
for _, member := range node.Members() {
|
||||
if ast.IsConstructorDeclaration(member) && ast.NodeIsPresent(member.Body()) {
|
||||
return member
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getEffectiveBaseTypeNode(node *ast.Node) *ast.Node {
|
||||
baseType := ast.GetClassExtendsHeritageElement(node)
|
||||
// !!! TODO: JSDoc support
|
||||
// if (baseType && isInJSFile(node)) {
|
||||
// // Prefer an @augments tag because it may have type parameters.
|
||||
// const tag = getJSDocAugmentsTag(node);
|
||||
// if (tag) {
|
||||
// return tag.class;
|
||||
// }
|
||||
// }
|
||||
return baseType
|
||||
}
|
||||
|
||||
func isScopeMarker(node *ast.Node) bool {
|
||||
return ast.IsExportAssignment(node) || ast.IsExportDeclaration(node)
|
||||
}
|
||||
|
||||
func hasScopeMarker(statements *ast.StatementList) bool {
|
||||
if statements == nil {
|
||||
return false
|
||||
}
|
||||
return core.Some(statements.Nodes, isScopeMarker)
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
package estransforms
|
||||
|
||||
import (
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers"
|
||||
)
|
||||
|
||||
type asyncTransformer struct {
|
||||
transformers.Transformer
|
||||
}
|
||||
|
||||
func (ch *asyncTransformer) visit(node *ast.Node) *ast.Node {
|
||||
return node // !!!
|
||||
}
|
||||
|
||||
func newAsyncTransformer(opts *transformers.TransformOptions) *transformers.Transformer {
|
||||
tx := &asyncTransformer{}
|
||||
return tx.NewTransformer(tx.visit, opts.Context)
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
package estransforms
|
||||
|
||||
import (
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers"
|
||||
)
|
||||
|
||||
type classFieldsTransformer struct {
|
||||
transformers.Transformer
|
||||
}
|
||||
|
||||
func (ch *classFieldsTransformer) visit(node *ast.Node) *ast.Node {
|
||||
return node // !!!
|
||||
}
|
||||
|
||||
func newClassFieldsTransformer(opts *transformers.TransformOptions) *transformers.Transformer {
|
||||
tx := &classFieldsTransformer{}
|
||||
return tx.NewTransformer(tx.visit, opts.Context)
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
package estransforms
|
||||
|
||||
import (
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers"
|
||||
)
|
||||
|
||||
type classStaticBlockTransformer struct {
|
||||
transformers.Transformer
|
||||
}
|
||||
|
||||
func (ch *classStaticBlockTransformer) visit(node *ast.Node) *ast.Node {
|
||||
return node // !!!
|
||||
}
|
||||
|
||||
func newClassStaticBlockTransformer(opts *transformers.TransformOptions) *transformers.Transformer {
|
||||
tx := &classStaticBlockTransformer{}
|
||||
return tx.NewTransformer(tx.visit, opts.Context)
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
package estransforms
|
||||
|
||||
import (
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
|
||||
)
|
||||
|
||||
// Gets whether a node is a `static {}` block containing only a single assignment of the static `this` to the `_classThis`
|
||||
// (or similar) variable stored in the `classthis` property of the block's `EmitNode`.
|
||||
func isClassThisAssignmentBlock(emitContext *printer.EmitContext, node *ast.Node) bool {
|
||||
if ast.IsClassStaticBlockDeclaration(node) {
|
||||
n := node.AsClassStaticBlockDeclaration()
|
||||
body := n.Body.AsBlock()
|
||||
if len(body.Statements.Nodes) == 1 {
|
||||
statement := body.Statements.Nodes[0]
|
||||
if ast.IsExpressionStatement(statement) {
|
||||
expression := statement.AsExpressionStatement().Expression
|
||||
if ast.IsAssignmentExpression(expression, true /*excludeCompoundAssignment*/) {
|
||||
binary := expression.AsBinaryExpression()
|
||||
return ast.IsIdentifier(binary.Left) &&
|
||||
emitContext.ClassThis(node) == binary.Left &&
|
||||
binary.Right.Kind == ast.KindThisKeyword
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@ -1,46 +0,0 @@
|
||||
package estransforms
|
||||
|
||||
import (
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers"
|
||||
)
|
||||
|
||||
// !!! TODO: This fixed layering scheme assumes you can't swap out the es decorator transform for the legacy one,
|
||||
// or the proper es class field transform for the legacy one
|
||||
var (
|
||||
NewESNextTransformer = transformers.Chain(newESDecoratorTransformer, newUsingDeclarationTransformer)
|
||||
// 2025: only module system syntax (import attributes, json modules), untransformed regex modifiers
|
||||
// 2024: no new downlevel syntax
|
||||
// 2023: no new downlevel syntax
|
||||
NewES2022Transformer = transformers.Chain(NewESNextTransformer, newClassStaticBlockTransformer, newClassFieldsTransformer) // !!! top level await? not transformed, just errored on at lower targets - also more of a module system feature anyway
|
||||
NewES2021Transformer = transformers.Chain(NewES2022Transformer, newLogicalAssignmentTransformer) // !!! numeric seperators? always elided by printer?
|
||||
NewES2020Transformer = transformers.Chain(NewES2021Transformer, newNullishCoalescingTransformer, newOptionalChainTransformer) // also dynamic import - module system feature
|
||||
NewES2019Transformer = transformers.Chain(NewES2020Transformer, newOptionalCatchTransformer)
|
||||
NewES2018Transformer = transformers.Chain(NewES2019Transformer, newObjectRestSpreadTransformer, newforawaitTransformer)
|
||||
NewES2017Transformer = transformers.Chain(NewES2018Transformer, newAsyncTransformer)
|
||||
NewES2016Transformer = transformers.Chain(NewES2017Transformer, newExponentiationTransformer)
|
||||
)
|
||||
|
||||
func GetESTransformer(opts *transformers.TransformOptions) *transformers.Transformer {
|
||||
options := opts.CompilerOptions
|
||||
switch options.GetEmitScriptTarget() {
|
||||
case core.ScriptTargetESNext:
|
||||
return nil // no transforms needed
|
||||
case /*core.ScriptTargetES2025,*/ core.ScriptTargetES2024, core.ScriptTargetES2023, core.ScriptTargetES2022:
|
||||
return NewESNextTransformer(opts)
|
||||
case core.ScriptTargetES2021:
|
||||
return NewES2022Transformer(opts)
|
||||
case core.ScriptTargetES2020:
|
||||
return NewES2021Transformer(opts)
|
||||
case core.ScriptTargetES2019:
|
||||
return NewES2020Transformer(opts)
|
||||
case core.ScriptTargetES2018:
|
||||
return NewES2019Transformer(opts)
|
||||
case core.ScriptTargetES2017:
|
||||
return NewES2018Transformer(opts)
|
||||
case core.ScriptTargetES2016:
|
||||
return NewES2017Transformer(opts)
|
||||
default: // other, older, option, transform maximally
|
||||
return NewES2016Transformer(opts)
|
||||
}
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
package estransforms
|
||||
|
||||
import (
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers"
|
||||
)
|
||||
|
||||
type esDecoratorTransformer struct {
|
||||
transformers.Transformer
|
||||
}
|
||||
|
||||
func (ch *esDecoratorTransformer) visit(node *ast.Node) *ast.Node {
|
||||
return node // !!!
|
||||
}
|
||||
|
||||
func newESDecoratorTransformer(opts *transformers.TransformOptions) *transformers.Transformer {
|
||||
tx := &esDecoratorTransformer{}
|
||||
return tx.NewTransformer(tx.visit, opts.Context)
|
||||
}
|
||||
@ -1,90 +0,0 @@
|
||||
package estransforms
|
||||
|
||||
import (
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers"
|
||||
)
|
||||
|
||||
type exponentiationTransformer struct {
|
||||
transformers.Transformer
|
||||
}
|
||||
|
||||
func (ch *exponentiationTransformer) visit(node *ast.Node) *ast.Node {
|
||||
if node.SubtreeFacts()&ast.SubtreeContainsExponentiationOperator == 0 {
|
||||
return node
|
||||
}
|
||||
switch node.Kind {
|
||||
case ast.KindBinaryExpression:
|
||||
return ch.visitBinaryExpression(node.AsBinaryExpression())
|
||||
default:
|
||||
return ch.Visitor().VisitEachChild(node)
|
||||
}
|
||||
}
|
||||
|
||||
func (ch *exponentiationTransformer) visitBinaryExpression(node *ast.BinaryExpression) *ast.Node {
|
||||
switch node.OperatorToken.Kind {
|
||||
case ast.KindAsteriskAsteriskEqualsToken:
|
||||
return ch.visitExponentiationAssignmentExpression(node)
|
||||
case ast.KindAsteriskAsteriskToken:
|
||||
return ch.visitExponentiationExpression(node)
|
||||
}
|
||||
return ch.Visitor().VisitEachChild(node.AsNode())
|
||||
}
|
||||
|
||||
func (ch *exponentiationTransformer) visitExponentiationAssignmentExpression(node *ast.BinaryExpression) *ast.Node {
|
||||
var target *ast.Node
|
||||
var value *ast.Node
|
||||
left := ch.Visitor().VisitNode(node.Left)
|
||||
right := ch.Visitor().VisitNode(node.Right)
|
||||
if ast.IsElementAccessExpression(left) {
|
||||
// Transforms `a[x] **= b` into `(_a = a)[_x = x] = Math.pow(_a[_x], b)`
|
||||
expressionTemp := ch.Factory().NewTempVariable()
|
||||
ch.EmitContext().AddVariableDeclaration(expressionTemp)
|
||||
argumentExpressionTemp := ch.Factory().NewTempVariable()
|
||||
ch.EmitContext().AddVariableDeclaration(argumentExpressionTemp)
|
||||
|
||||
objExpr := ch.Factory().NewAssignmentExpression(expressionTemp, left.AsElementAccessExpression().Expression)
|
||||
objExpr.Loc = left.AsElementAccessExpression().Expression.Loc
|
||||
accessExpr := ch.Factory().NewAssignmentExpression(argumentExpressionTemp, left.AsElementAccessExpression().ArgumentExpression)
|
||||
accessExpr.Loc = left.AsElementAccessExpression().ArgumentExpression.Loc
|
||||
|
||||
target = ch.Factory().NewElementAccessExpression(objExpr, nil, accessExpr, ast.NodeFlagsNone)
|
||||
|
||||
value = ch.Factory().NewElementAccessExpression(expressionTemp, nil, argumentExpressionTemp, ast.NodeFlagsNone)
|
||||
value.Loc = left.Loc
|
||||
} else if ast.IsPropertyAccessExpression(left) {
|
||||
// Transforms `a.x **= b` into `(_a = a).x = Math.pow(_a.x, b)`
|
||||
expressionTemp := ch.Factory().NewTempVariable()
|
||||
ch.EmitContext().AddVariableDeclaration(expressionTemp)
|
||||
assignment := ch.Factory().NewAssignmentExpression(expressionTemp, left.Expression())
|
||||
assignment.Loc = left.Expression().Loc
|
||||
target = ch.Factory().NewPropertyAccessExpression(assignment, nil, left.Name(), ast.NodeFlagsNone)
|
||||
target.Loc = left.Loc
|
||||
|
||||
value = ch.Factory().NewPropertyAccessExpression(expressionTemp, nil, left.Name(), ast.NodeFlagsNone)
|
||||
value.Loc = left.Loc
|
||||
} else {
|
||||
// Transforms `a **= b` into `a = Math.pow(a, b)`
|
||||
target = left
|
||||
value = left
|
||||
}
|
||||
|
||||
rhs := ch.Factory().NewGlobalMethodCall("Math", "pow", []*ast.Node{value, right})
|
||||
rhs.Loc = node.Loc
|
||||
result := ch.Factory().NewAssignmentExpression(target, rhs)
|
||||
result.Loc = node.Loc
|
||||
return result
|
||||
}
|
||||
|
||||
func (ch *exponentiationTransformer) visitExponentiationExpression(node *ast.BinaryExpression) *ast.Node {
|
||||
left := ch.Visitor().VisitNode(node.Left)
|
||||
right := ch.Visitor().VisitNode(node.Right)
|
||||
result := ch.Factory().NewGlobalMethodCall("Math", "pow", []*ast.Node{left, right})
|
||||
result.Loc = node.Loc
|
||||
return result
|
||||
}
|
||||
|
||||
func newExponentiationTransformer(opts *transformers.TransformOptions) *transformers.Transformer {
|
||||
tx := &exponentiationTransformer{}
|
||||
return tx.NewTransformer(tx.visit, opts.Context)
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
package estransforms
|
||||
|
||||
import (
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers"
|
||||
)
|
||||
|
||||
type forawaitTransformer struct {
|
||||
transformers.Transformer
|
||||
}
|
||||
|
||||
func (ch *forawaitTransformer) visit(node *ast.Node) *ast.Node {
|
||||
return node // !!!
|
||||
}
|
||||
|
||||
func newforawaitTransformer(opts *transformers.TransformOptions) *transformers.Transformer {
|
||||
tx := &forawaitTransformer{}
|
||||
return tx.NewTransformer(tx.visit, opts.Context)
|
||||
}
|
||||
@ -1,113 +0,0 @@
|
||||
package estransforms
|
||||
|
||||
import (
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers"
|
||||
)
|
||||
|
||||
type logicalAssignmentTransformer struct {
|
||||
transformers.Transformer
|
||||
}
|
||||
|
||||
func (ch *logicalAssignmentTransformer) visit(node *ast.Node) *ast.Node {
|
||||
if node.SubtreeFacts()&ast.SubtreeContainsLogicalAssignments == 0 {
|
||||
return node
|
||||
}
|
||||
switch node.Kind {
|
||||
case ast.KindBinaryExpression:
|
||||
return ch.visitBinaryExpression(node.AsBinaryExpression())
|
||||
default:
|
||||
return ch.Visitor().VisitEachChild(node)
|
||||
}
|
||||
}
|
||||
|
||||
func (ch *logicalAssignmentTransformer) visitBinaryExpression(node *ast.BinaryExpression) *ast.Node {
|
||||
var nonAssignmentOperator ast.Kind
|
||||
switch node.OperatorToken.Kind {
|
||||
case ast.KindBarBarEqualsToken:
|
||||
nonAssignmentOperator = ast.KindBarBarToken
|
||||
case ast.KindAmpersandAmpersandEqualsToken:
|
||||
nonAssignmentOperator = ast.KindAmpersandAmpersandToken
|
||||
case ast.KindQuestionQuestionEqualsToken:
|
||||
nonAssignmentOperator = ast.KindQuestionQuestionToken
|
||||
default:
|
||||
return ch.Visitor().VisitEachChild(node.AsNode())
|
||||
}
|
||||
|
||||
left := ast.SkipParentheses(ch.Visitor().VisitNode(node.Left))
|
||||
assignmentTarget := left
|
||||
right := ast.SkipParentheses(ch.Visitor().VisitNode(node.Right))
|
||||
|
||||
if ast.IsAccessExpression(left) {
|
||||
propertyAccessTargetSimpleCopiable := transformers.IsSimpleCopiableExpression(left.Expression())
|
||||
propertyAccessTarget := left.Expression()
|
||||
propertyAccessTargetAssignment := left.Expression()
|
||||
if !propertyAccessTargetSimpleCopiable {
|
||||
propertyAccessTarget = ch.Factory().NewTempVariable()
|
||||
ch.EmitContext().AddVariableDeclaration(propertyAccessTarget)
|
||||
propertyAccessTargetAssignment = ch.Factory().NewAssignmentExpression(
|
||||
propertyAccessTarget,
|
||||
left.Expression(),
|
||||
)
|
||||
}
|
||||
|
||||
if ast.IsPropertyAccessExpression(left) {
|
||||
assignmentTarget = ch.Factory().NewPropertyAccessExpression(
|
||||
propertyAccessTarget,
|
||||
nil,
|
||||
left.Name(),
|
||||
ast.NodeFlagsNone,
|
||||
)
|
||||
left = ch.Factory().NewPropertyAccessExpression(
|
||||
propertyAccessTargetAssignment,
|
||||
nil,
|
||||
left.Name(),
|
||||
ast.NodeFlagsNone,
|
||||
)
|
||||
} else {
|
||||
elementAccessArgumentSimpleCopiable := transformers.IsSimpleCopiableExpression(left.AsElementAccessExpression().ArgumentExpression)
|
||||
elementAccessArgument := left.AsElementAccessExpression().ArgumentExpression
|
||||
argumentExpr := elementAccessArgument
|
||||
if !elementAccessArgumentSimpleCopiable {
|
||||
elementAccessArgument = ch.Factory().NewTempVariable()
|
||||
ch.EmitContext().AddVariableDeclaration(elementAccessArgument)
|
||||
argumentExpr = ch.Factory().NewAssignmentExpression(
|
||||
elementAccessArgument,
|
||||
left.AsElementAccessExpression().ArgumentExpression,
|
||||
)
|
||||
}
|
||||
|
||||
assignmentTarget = ch.Factory().NewElementAccessExpression(
|
||||
propertyAccessTarget,
|
||||
nil,
|
||||
elementAccessArgument,
|
||||
ast.NodeFlagsNone,
|
||||
)
|
||||
left = ch.Factory().NewElementAccessExpression(
|
||||
propertyAccessTargetAssignment,
|
||||
nil,
|
||||
argumentExpr,
|
||||
ast.NodeFlagsNone,
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ch.Factory().NewBinaryExpression(
|
||||
nil,
|
||||
left,
|
||||
nil,
|
||||
ch.Factory().NewToken(nonAssignmentOperator),
|
||||
ch.Factory().NewParenthesizedExpression(
|
||||
ch.Factory().NewAssignmentExpression(
|
||||
assignmentTarget,
|
||||
right,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
func newLogicalAssignmentTransformer(opts *transformers.TransformOptions) *transformers.Transformer {
|
||||
tx := &logicalAssignmentTransformer{}
|
||||
return tx.NewTransformer(tx.visit, opts.Context)
|
||||
}
|
||||
@ -1,560 +0,0 @@
|
||||
package estransforms
|
||||
|
||||
import (
|
||||
"slices"
|
||||
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
|
||||
)
|
||||
|
||||
/**
|
||||
* Gets whether a node is a `static {}` block containing only a single call to the `__setFunctionName` helper where that
|
||||
* call's second argument is the value stored in the `assignedName` property of the block's `EmitNode`.
|
||||
* @internal
|
||||
*/
|
||||
func isClassNamedEvaluationHelperBlock(emitContext *printer.EmitContext, node *ast.Node) bool {
|
||||
if !ast.IsClassStaticBlockDeclaration(node) || len(node.AsClassStaticBlockDeclaration().Body.AsBlock().Statements.Nodes) != 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
statement := node.AsClassStaticBlockDeclaration().Body.AsBlock().Statements.Nodes[0]
|
||||
if ast.IsExpressionStatement(statement) {
|
||||
expression := statement.AsExpressionStatement().Expression
|
||||
if emitContext.IsCallToHelper(expression, "__setFunctionName") {
|
||||
arguments := expression.AsCallExpression().Arguments
|
||||
return len(arguments.Nodes) >= 2 &&
|
||||
arguments.Nodes[1] == emitContext.AssignedName(node.AsNode())
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether a `ClassLikeDeclaration` has a `static {}` block containing only a single call to the
|
||||
* `__setFunctionName` helper.
|
||||
* @internal
|
||||
*/
|
||||
func classHasExplicitlyAssignedName(emitContext *printer.EmitContext, node *ast.ClassLikeDeclaration) bool {
|
||||
if assignedName := emitContext.AssignedName(node); assignedName != nil {
|
||||
for _, member := range node.Members() {
|
||||
if isClassNamedEvaluationHelperBlock(emitContext, member) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether a `ClassLikeDeclaration` has a declared name or contains a `static {}` block containing only a single
|
||||
* call to the `__setFunctionName` helper.
|
||||
* @internal
|
||||
*/
|
||||
func classHasDeclaredOrExplicitlyAssignedName(emitContext *printer.EmitContext, node *ast.ClassLikeDeclaration) bool {
|
||||
return node.Name() != nil || classHasExplicitlyAssignedName(emitContext, node)
|
||||
}
|
||||
|
||||
// Indicates whether a property name is the special `__proto__` property.
|
||||
// Per the ECMA-262 spec, this only matters for property assignments whose name is
|
||||
// the Identifier `__proto__`, or the string literal `"__proto__"`, but not for
|
||||
// computed property names.
|
||||
func isProtoSetter(node *ast.PropertyName) bool {
|
||||
return ast.IsIdentifier(node) || ast.IsStringLiteral(node) && node.Text() == "__proto__"
|
||||
}
|
||||
|
||||
type anonymousFunctionDefinition = ast.Node // ClassExpression | FunctionExpression | ArrowFunction
|
||||
|
||||
// Indicates whether an expression is an anonymous function definition.
|
||||
//
|
||||
// See https://tc39.es/ecma262/#sec-isanonymousfunctiondefinition
|
||||
func isAnonymousFunctionDefinition(emitContext *printer.EmitContext, node *ast.Expression, cb func(*anonymousFunctionDefinition) bool) bool {
|
||||
node = ast.SkipOuterExpressions(node, ast.OEKAll)
|
||||
switch node.Kind {
|
||||
case ast.KindClassExpression:
|
||||
if classHasDeclaredOrExplicitlyAssignedName(emitContext, node) {
|
||||
return false
|
||||
}
|
||||
break
|
||||
case ast.KindFunctionExpression:
|
||||
if node.AsFunctionExpression().Name() != nil {
|
||||
return false
|
||||
}
|
||||
break
|
||||
case ast.KindArrowFunction:
|
||||
break
|
||||
default:
|
||||
return false
|
||||
}
|
||||
if cb != nil {
|
||||
return cb(node)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Indicates whether a node is a potential source of an assigned name for a class, function, or arrow function.
|
||||
func isNamedEvaluationSource(node *ast.Node) bool {
|
||||
switch node.Kind {
|
||||
case ast.KindPropertyAssignment:
|
||||
return !isProtoSetter(node.AsPropertyAssignment().Name())
|
||||
case ast.KindShorthandPropertyAssignment:
|
||||
return node.AsShorthandPropertyAssignment().ObjectAssignmentInitializer != nil
|
||||
case ast.KindVariableDeclaration:
|
||||
return ast.IsIdentifier(node.AsVariableDeclaration().Name()) && node.AsVariableDeclaration().Initializer != nil
|
||||
case ast.KindParameter:
|
||||
return ast.IsIdentifier(node.AsParameterDeclaration().Name()) && node.AsParameterDeclaration().Initializer != nil && node.AsParameterDeclaration().DotDotDotToken == nil
|
||||
case ast.KindBindingElement:
|
||||
return ast.IsIdentifier(node.AsBindingElement().Name()) && node.AsBindingElement().Initializer != nil && node.AsBindingElement().DotDotDotToken == nil
|
||||
case ast.KindPropertyDeclaration:
|
||||
return node.AsPropertyDeclaration().Initializer != nil
|
||||
case ast.KindBinaryExpression:
|
||||
switch node.AsBinaryExpression().OperatorToken.Kind {
|
||||
case ast.KindEqualsToken, ast.KindAmpersandAmpersandEqualsToken, ast.KindBarBarEqualsToken, ast.KindQuestionQuestionEqualsToken:
|
||||
return ast.IsIdentifier(node.AsBinaryExpression().Left)
|
||||
}
|
||||
break
|
||||
case ast.KindExportAssignment:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isNamedEvaluation(emitContext *printer.EmitContext, node *ast.Node) bool {
|
||||
return isNamedEvaluationAnd(emitContext, node, nil)
|
||||
}
|
||||
|
||||
func isNamedEvaluationAnd(emitContext *printer.EmitContext, node *ast.Node, cb func(*anonymousFunctionDefinition) bool) bool {
|
||||
if !isNamedEvaluationSource(node) {
|
||||
return false
|
||||
}
|
||||
switch node.Kind {
|
||||
case ast.KindShorthandPropertyAssignment:
|
||||
return isAnonymousFunctionDefinition(emitContext, node.AsShorthandPropertyAssignment().ObjectAssignmentInitializer, cb)
|
||||
case ast.KindPropertyAssignment, ast.KindVariableDeclaration, ast.KindParameter, ast.KindBindingElement, ast.KindPropertyDeclaration:
|
||||
return isAnonymousFunctionDefinition(emitContext, node.Initializer(), cb)
|
||||
case ast.KindBinaryExpression:
|
||||
return isAnonymousFunctionDefinition(emitContext, node.AsBinaryExpression().Right, cb)
|
||||
case ast.KindExportAssignment:
|
||||
return isAnonymousFunctionDefinition(emitContext, node.AsExportAssignment().Expression, cb)
|
||||
default:
|
||||
panic("Unhandled case in isNamedEvaluation")
|
||||
}
|
||||
}
|
||||
|
||||
// Gets a string literal to use as the assigned name of an anonymous class or function declaration.
|
||||
func getAssignedNameOfIdentifier(emitContext *printer.EmitContext, name *ast.IdentifierNode, expression *ast.Node /*WrappedExpression<AnonymousFunctionDefinition>*/) *ast.StringLiteralNode {
|
||||
original := emitContext.MostOriginal(ast.SkipOuterExpressions(expression, ast.OEKAll))
|
||||
if (ast.IsClassDeclaration(original) || ast.IsFunctionDeclaration(original)) &&
|
||||
original.Name() == nil && ast.HasSyntacticModifier(original, ast.ModifierFlagsDefault) {
|
||||
return emitContext.Factory.NewStringLiteral("default")
|
||||
}
|
||||
return emitContext.Factory.NewStringLiteralFromNode(name)
|
||||
}
|
||||
|
||||
func getAssignedNameOfPropertyName(emitContext *printer.EmitContext, name *ast.PropertyName, assignedNameText string) (assignedName *ast.Expression, updatedName *ast.PropertyName) {
|
||||
factory := emitContext.Factory
|
||||
if len(assignedNameText) > 0 {
|
||||
assignedName := factory.NewStringLiteral(assignedNameText)
|
||||
return assignedName, name
|
||||
}
|
||||
|
||||
if ast.IsPropertyNameLiteral(name) || ast.IsPrivateIdentifier(name) {
|
||||
assignedName := factory.NewStringLiteralFromNode(name)
|
||||
return assignedName, name
|
||||
}
|
||||
|
||||
expression := name.Expression()
|
||||
if ast.IsPropertyNameLiteral(expression) && !ast.IsIdentifier(expression) {
|
||||
assignedName := factory.NewStringLiteralFromNode(expression)
|
||||
return assignedName, name
|
||||
}
|
||||
|
||||
if !ast.IsComputedPropertyName(expression) {
|
||||
panic("Expected computed property name")
|
||||
}
|
||||
|
||||
assignedName = factory.NewGeneratedNameForNode(name)
|
||||
emitContext.AddVariableDeclaration(assignedName)
|
||||
|
||||
key := factory.NewPropKeyHelper(expression)
|
||||
assignment := factory.NewAssignmentExpression(assignedName, key)
|
||||
updatedName = factory.UpdateComputedPropertyName(name.AsComputedPropertyName(), assignment)
|
||||
return assignedName, updatedName
|
||||
}
|
||||
|
||||
// Creates a class `static {}` block used to dynamically set the name of a class.
|
||||
//
|
||||
// The assignedName parameter is the expression used to resolve the assigned name at runtime. This expression should not produce
|
||||
// side effects.
|
||||
// The thisExpression parameter overrides the expression to use for the actual `this` reference. This can be used to provide an
|
||||
// expression that has already had its `EmitFlags` set or may have been tracked to prevent substitution.
|
||||
func createClassNamedEvaluationHelperBlock(emitContext *printer.EmitContext, assignedName *ast.Expression, thisExpression *ast.Expression) *ast.Node {
|
||||
// produces:
|
||||
//
|
||||
// static { __setFunctionName(this, "C"); }
|
||||
//
|
||||
|
||||
if thisExpression == nil {
|
||||
thisExpression = emitContext.Factory.NewThisExpression()
|
||||
}
|
||||
|
||||
factory := emitContext.Factory
|
||||
expression := factory.NewSetFunctionNameHelper(thisExpression, assignedName, "" /*prefix*/)
|
||||
statement := factory.NewExpressionStatement(expression)
|
||||
body := factory.NewBlock(factory.NewNodeList([]*ast.Statement{statement}), false /*multiLine*/)
|
||||
block := factory.NewClassStaticBlockDeclaration(nil /*modifiers*/, body)
|
||||
|
||||
// We use `emitNode.assignedName` to indicate this is a NamedEvaluation helper block
|
||||
// and to stash the expression used to resolve the assigned name.
|
||||
emitContext.SetAssignedName(block, assignedName)
|
||||
return block.AsNode()
|
||||
}
|
||||
|
||||
// Injects a class `static {}` block used to dynamically set the name of a class, if one does not already exist.
|
||||
func injectClassNamedEvaluationHelperBlockIfMissing(
|
||||
emitContext *printer.EmitContext,
|
||||
node *ast.ClassLikeDeclaration,
|
||||
assignedName *ast.Expression,
|
||||
thisExpression *ast.Expression,
|
||||
) *ast.ClassLikeDeclaration {
|
||||
// given:
|
||||
//
|
||||
// let C = class {
|
||||
// };
|
||||
//
|
||||
// produces:
|
||||
//
|
||||
// let C = class {
|
||||
// static { __setFunctionName(this, "C"); }
|
||||
// };
|
||||
|
||||
// NOTE: If the class has a `_classThis` assignment block, this helper will be injected after that block.
|
||||
|
||||
if classHasExplicitlyAssignedName(emitContext, node) {
|
||||
return node
|
||||
}
|
||||
|
||||
factory := emitContext.Factory
|
||||
namedEvaluationBlock := createClassNamedEvaluationHelperBlock(emitContext, assignedName, thisExpression)
|
||||
if node.Name() != nil {
|
||||
emitContext.SetSourceMapRange(namedEvaluationBlock.Body().AsBlock().Statements.Nodes[0], node.Name().Loc)
|
||||
}
|
||||
|
||||
insertionIndex := slices.IndexFunc(node.Members(), func(n *ast.Node) bool {
|
||||
return isClassThisAssignmentBlock(emitContext, n)
|
||||
}) + 1
|
||||
leading := slices.Clone(node.Members()[:insertionIndex])
|
||||
trailing := slices.Clone(node.Members()[insertionIndex:])
|
||||
|
||||
var members []*ast.ClassElement
|
||||
members = append(members, leading...)
|
||||
members = append(members, namedEvaluationBlock)
|
||||
members = append(members, trailing...)
|
||||
membersList := factory.NewNodeList(members)
|
||||
membersList.Loc = node.MemberList().Loc
|
||||
|
||||
if ast.IsClassDeclaration(node) {
|
||||
node = factory.UpdateClassDeclaration(
|
||||
node.AsClassDeclaration(),
|
||||
node.Modifiers(),
|
||||
node.Name(),
|
||||
node.TypeParameterList(),
|
||||
node.AsClassDeclaration().HeritageClauses,
|
||||
membersList,
|
||||
)
|
||||
} else {
|
||||
node = factory.UpdateClassExpression(
|
||||
node.AsClassExpression(),
|
||||
node.Modifiers(),
|
||||
node.Name(),
|
||||
node.TypeParameterList(),
|
||||
node.AsClassExpression().HeritageClauses,
|
||||
membersList,
|
||||
)
|
||||
}
|
||||
|
||||
emitContext.SetAssignedName(node, assignedName)
|
||||
return node
|
||||
}
|
||||
|
||||
func finishTransformNamedEvaluation(
|
||||
emitContext *printer.EmitContext,
|
||||
expression *ast.Node, // WrappedExpression<AnonymousFunctionDefinition>,
|
||||
assignedName *ast.Expression,
|
||||
ignoreEmptyStringLiteral bool,
|
||||
) *ast.Expression {
|
||||
if ignoreEmptyStringLiteral && ast.IsStringLiteral(assignedName) && len(assignedName.Text()) == 0 {
|
||||
return expression
|
||||
}
|
||||
|
||||
factory := emitContext.Factory
|
||||
innerExpression := ast.SkipOuterExpressions(expression, ast.OEKAll)
|
||||
|
||||
var updatedExpression *ast.Expression
|
||||
if ast.IsClassExpression(innerExpression) {
|
||||
updatedExpression = injectClassNamedEvaluationHelperBlockIfMissing(emitContext, innerExpression, assignedName, nil /*thisExpression*/)
|
||||
} else {
|
||||
updatedExpression = factory.NewSetFunctionNameHelper(innerExpression, assignedName, "" /*prefix*/)
|
||||
}
|
||||
|
||||
return factory.RestoreOuterExpressions(expression, updatedExpression, ast.OEKAll)
|
||||
}
|
||||
|
||||
func transformNamedEvaluationOfPropertyAssignment(context *printer.EmitContext, node *ast.PropertyAssignment /*NamedEvaluation & PropertyAssignment*/, ignoreEmptyStringLiteral bool, assignedNameText string) *ast.Expression {
|
||||
// 13.2.5.5 RS: PropertyDefinitionEvaluation
|
||||
// PropertyAssignment : PropertyName `:` AssignmentExpression
|
||||
// ...
|
||||
// 5. If IsAnonymousFunctionDefinition(|AssignmentExpression|) is *true* and _isProtoSetter_ is *false*, then
|
||||
// a. Let _popValue_ be ? NamedEvaluation of |AssignmentExpression| with argument _propKey_.
|
||||
// ...
|
||||
|
||||
factory := context.Factory
|
||||
assignedName, name := getAssignedNameOfPropertyName(context, node.Name(), assignedNameText)
|
||||
initializer := finishTransformNamedEvaluation(context, node.Initializer, assignedName, ignoreEmptyStringLiteral)
|
||||
return factory.UpdatePropertyAssignment(node, nil /*modifiers*/, name, nil /*postfixToken*/, nil /*typeNode*/, initializer)
|
||||
}
|
||||
|
||||
func transformNamedEvaluationOfShorthandAssignmentProperty(emitContext *printer.EmitContext, node *ast.ShorthandPropertyAssignment /*NamedEvaluation & ShorthandPropertyAssignment*/, ignoreEmptyStringLiteral bool, assignedNameText string) *ast.Expression {
|
||||
// 13.15.5.3 RS: PropertyDestructuringAssignmentEvaluation
|
||||
// AssignmentProperty : IdentifierReference Initializer?
|
||||
// ...
|
||||
// 4. If |Initializer?| is present and _v_ is *undefined*, then
|
||||
// a. If IsAnonymousFunctionDefinition(|Initializer|) is *true*, then
|
||||
// i. Set _v_ to ? NamedEvaluation of |Initializer| with argument _P_.
|
||||
// ...
|
||||
|
||||
factory := emitContext.Factory
|
||||
var assignedName *ast.Expression
|
||||
if len(assignedNameText) > 0 {
|
||||
assignedName = factory.NewStringLiteral(assignedNameText)
|
||||
} else {
|
||||
assignedName = getAssignedNameOfIdentifier(emitContext, node.Name(), node.ObjectAssignmentInitializer)
|
||||
}
|
||||
objectAssignmentInitializer := finishTransformNamedEvaluation(emitContext, node.ObjectAssignmentInitializer, assignedName, ignoreEmptyStringLiteral)
|
||||
return factory.UpdateShorthandPropertyAssignment(
|
||||
node,
|
||||
nil, /*modifiers*/
|
||||
node.Name(),
|
||||
nil, /*postfixToken*/
|
||||
nil, /*typeNode*/
|
||||
node.EqualsToken,
|
||||
objectAssignmentInitializer,
|
||||
)
|
||||
}
|
||||
|
||||
func transformNamedEvaluationOfVariableDeclaration(emitContext *printer.EmitContext, node *ast.VariableDeclaration /*NamedEvaluation & VariableDeclaration*/, ignoreEmptyStringLiteral bool, assignedNameText string) *ast.Expression {
|
||||
// 14.3.1.2 RS: Evaluation
|
||||
// LexicalBinding : BindingIdentifier Initializer
|
||||
// ...
|
||||
// 3. If IsAnonymousFunctionDefinition(|Initializer|) is *true*, then
|
||||
// a. Let _value_ be ? NamedEvaluation of |Initializer| with argument _bindingId_.
|
||||
// ...
|
||||
//
|
||||
// 14.3.2.1 RS: Evaluation
|
||||
// VariableDeclaration : BindingIdentifier Initializer
|
||||
// ...
|
||||
// 3. If IsAnonymousFunctionDefinition(|Initializer|) is *true*, then
|
||||
// a. Let _value_ be ? NamedEvaluation of |Initializer| with argument _bindingId_.
|
||||
// ...
|
||||
|
||||
factory := emitContext.Factory
|
||||
var assignedName *ast.Expression
|
||||
if len(assignedNameText) > 0 {
|
||||
assignedName = factory.NewStringLiteral(assignedNameText)
|
||||
} else {
|
||||
assignedName = getAssignedNameOfIdentifier(emitContext, node.Name(), node.Initializer)
|
||||
}
|
||||
initializer := finishTransformNamedEvaluation(emitContext, node.Initializer, assignedName, ignoreEmptyStringLiteral)
|
||||
return factory.UpdateVariableDeclaration(
|
||||
node,
|
||||
node.Name(),
|
||||
nil, /*exclamationToken*/
|
||||
nil, /*typeNode*/
|
||||
initializer,
|
||||
)
|
||||
}
|
||||
|
||||
func transformNamedEvaluationOfParameterDeclaration(emitContext *printer.EmitContext, node *ast.ParameterDeclaration /*NamedEvaluation & ParameterDeclaration*/, ignoreEmptyStringLiteral bool, assignedNameText string) *ast.Expression {
|
||||
// 8.6.3 RS: IteratorBindingInitialization
|
||||
// SingleNameBinding : BindingIdentifier Initializer?
|
||||
// ...
|
||||
// 5. If |Initializer| is present and _v_ is *undefined*, then
|
||||
// a. If IsAnonymousFunctionDefinition(|Initializer|) is *true*, then
|
||||
// i. Set _v_ to ? NamedEvaluation of |Initializer| with argument _bindingId_.
|
||||
// ...
|
||||
//
|
||||
// 14.3.3.3 RS: KeyedBindingInitialization
|
||||
// SingleNameBinding : BindingIdentifier Initializer?
|
||||
// ...
|
||||
// 4. If |Initializer| is present and _v_ is *undefined*, then
|
||||
// a. If IsAnonymousFunctionDefinition(|Initializer|) is *true*, then
|
||||
// i. Set _v_ to ? NamedEvaluation of |Initializer| with argument _bindingId_.
|
||||
// ...
|
||||
|
||||
factory := emitContext.Factory
|
||||
var assignedName *ast.Expression
|
||||
if len(assignedNameText) > 0 {
|
||||
assignedName = factory.NewStringLiteral(assignedNameText)
|
||||
} else {
|
||||
assignedName = getAssignedNameOfIdentifier(emitContext, node.Name(), node.Initializer)
|
||||
}
|
||||
initializer := finishTransformNamedEvaluation(emitContext, node.Initializer, assignedName, ignoreEmptyStringLiteral)
|
||||
return factory.UpdateParameterDeclaration(
|
||||
node,
|
||||
nil, /*modifiers*/
|
||||
node.DotDotDotToken,
|
||||
node.Name(),
|
||||
nil, /*questionToken*/
|
||||
nil, /*typeNode*/
|
||||
initializer,
|
||||
)
|
||||
}
|
||||
|
||||
func transformNamedEvaluationOfBindingElement(emitContext *printer.EmitContext, node *ast.BindingElement /*NamedEvaluation & BindingElement*/, ignoreEmptyStringLiteral bool, assignedNameText string) *ast.Expression {
|
||||
// 8.6.3 RS: IteratorBindingInitialization
|
||||
// SingleNameBinding : BindingIdentifier Initializer?
|
||||
// ...
|
||||
// 5. If |Initializer| is present and _v_ is *undefined*, then
|
||||
// a. If IsAnonymousFunctionDefinition(|Initializer|) is *true*, then
|
||||
// i. Set _v_ to ? NamedEvaluation of |Initializer| with argument _bindingId_.
|
||||
// ...
|
||||
//
|
||||
// 14.3.3.3 RS: KeyedBindingInitialization
|
||||
// SingleNameBinding : BindingIdentifier Initializer?
|
||||
// ...
|
||||
// 4. If |Initializer| is present and _v_ is *undefined*, then
|
||||
// a. If IsAnonymousFunctionDefinition(|Initializer|) is *true*, then
|
||||
// i. Set _v_ to ? NamedEvaluation of |Initializer| with argument _bindingId_.
|
||||
// ...
|
||||
|
||||
factory := emitContext.Factory
|
||||
var assignedName *ast.Expression
|
||||
if len(assignedNameText) > 0 {
|
||||
assignedName = factory.NewStringLiteral(assignedNameText)
|
||||
} else {
|
||||
assignedName = getAssignedNameOfIdentifier(emitContext, node.Name(), node.Initializer)
|
||||
}
|
||||
initializer := finishTransformNamedEvaluation(emitContext, node.Initializer, assignedName, ignoreEmptyStringLiteral)
|
||||
return factory.UpdateBindingElement(
|
||||
node,
|
||||
node.DotDotDotToken,
|
||||
node.PropertyName,
|
||||
node.Name(),
|
||||
initializer,
|
||||
)
|
||||
}
|
||||
|
||||
func transformNamedEvaluationOfPropertyDeclaration(emitContext *printer.EmitContext, node *ast.PropertyDeclaration /*NamedEvaluation & PropertyDeclaration*/, ignoreEmptyStringLiteral bool, assignedNameText string) *ast.Expression {
|
||||
// 10.2.1.3 RS: EvaluateBody
|
||||
// Initializer : `=` AssignmentExpression
|
||||
// ...
|
||||
// 3. If IsAnonymousFunctionDefinition(|AssignmentExpression|) is *true*, then
|
||||
// a. Let _value_ be ? NamedEvaluation of |Initializer| with argument _functionObject_.[[ClassFieldInitializerName]].
|
||||
// ...
|
||||
|
||||
factory := emitContext.Factory
|
||||
assignedName, name := getAssignedNameOfPropertyName(emitContext, node.Name(), assignedNameText)
|
||||
initializer := finishTransformNamedEvaluation(emitContext, node.Initializer, assignedName, ignoreEmptyStringLiteral)
|
||||
return factory.UpdatePropertyDeclaration(
|
||||
node,
|
||||
node.Modifiers(),
|
||||
name,
|
||||
nil, /*postfixToken*/
|
||||
nil, /*typeNode*/
|
||||
initializer,
|
||||
)
|
||||
}
|
||||
|
||||
func transformNamedEvaluationOfAssignmentExpression(emitContext *printer.EmitContext, node *ast.BinaryExpression /*NamedEvaluation & BinaryExpression*/, ignoreEmptyStringLiteral bool, assignedNameText string) *ast.Expression {
|
||||
// 13.15.2 RS: Evaluation
|
||||
// AssignmentExpression : LeftHandSideExpression `=` AssignmentExpression
|
||||
// 1. If |LeftHandSideExpression| is neither an |ObjectLiteral| nor an |ArrayLiteral|, then
|
||||
// a. Let _lref_ be ? Evaluation of |LeftHandSideExpression|.
|
||||
// b. If IsAnonymousFunctionDefinition(|AssignmentExpression|) and IsIdentifierRef of |LeftHandSideExpression| are both *true*, then
|
||||
// i. Let _rval_ be ? NamedEvaluation of |AssignmentExpression| with argument _lref_.[[ReferencedName]].
|
||||
// ...
|
||||
//
|
||||
// AssignmentExpression : LeftHandSideExpression `&&=` AssignmentExpression
|
||||
// ...
|
||||
// 5. If IsAnonymousFunctionDefinition(|AssignmentExpression|) is *true* and IsIdentifierRef of |LeftHandSideExpression| is *true*, then
|
||||
// a. Let _rval_ be ? NamedEvaluation of |AssignmentExpression| with argument _lref_.[[ReferencedName]].
|
||||
// ...
|
||||
//
|
||||
// AssignmentExpression : LeftHandSideExpression `||=` AssignmentExpression
|
||||
// ...
|
||||
// 5. If IsAnonymousFunctionDefinition(|AssignmentExpression|) is *true* and IsIdentifierRef of |LeftHandSideExpression| is *true*, then
|
||||
// a. Let _rval_ be ? NamedEvaluation of |AssignmentExpression| with argument _lref_.[[ReferencedName]].
|
||||
// ...
|
||||
//
|
||||
// AssignmentExpression : LeftHandSideExpression `??=` AssignmentExpression
|
||||
// ...
|
||||
// 4. If IsAnonymousFunctionDefinition(|AssignmentExpression|) is *true* and IsIdentifierRef of |LeftHandSideExpression| is *true*, then
|
||||
// a. Let _rval_ be ? NamedEvaluation of |AssignmentExpression| with argument _lref_.[[ReferencedName]].
|
||||
// ...
|
||||
|
||||
factory := emitContext.Factory
|
||||
var assignedName *ast.Expression
|
||||
if len(assignedNameText) > 0 {
|
||||
assignedName = factory.NewStringLiteral(assignedNameText)
|
||||
} else {
|
||||
assignedName = getAssignedNameOfIdentifier(emitContext, node.Left, node.Right)
|
||||
}
|
||||
right := finishTransformNamedEvaluation(emitContext, node.Right, assignedName, ignoreEmptyStringLiteral)
|
||||
return factory.UpdateBinaryExpression(
|
||||
node,
|
||||
nil, /*modifiers*/
|
||||
node.Left,
|
||||
nil, /*typeNode*/
|
||||
node.OperatorToken,
|
||||
right,
|
||||
)
|
||||
}
|
||||
|
||||
func transformNamedEvaluationOfExportAssignment(emitContext *printer.EmitContext, node *ast.ExportAssignment /*NamedEvaluation & ExportAssignment*/, ignoreEmptyStringLiteral bool, assignedNameText string) *ast.Expression {
|
||||
// 16.2.3.7 RS: Evaluation
|
||||
// ExportDeclaration : `export` `default` AssignmentExpression `;`
|
||||
// 1. If IsAnonymousFunctionDefinition(|AssignmentExpression|) is *true*, then
|
||||
// a. Let _value_ be ? NamedEvaluation of |AssignmentExpression| with argument `"default"`.
|
||||
// ...
|
||||
|
||||
// NOTE: Since emit for `export =` translates to `module.exports = ...`, the assigned name of the class or function
|
||||
// is `""`.
|
||||
|
||||
factory := emitContext.Factory
|
||||
var assignedName *ast.Expression
|
||||
if len(assignedNameText) > 0 {
|
||||
assignedName = factory.NewStringLiteral(assignedNameText)
|
||||
} else {
|
||||
assignedName = factory.NewStringLiteral("")
|
||||
}
|
||||
expression := finishTransformNamedEvaluation(emitContext, node.Expression, assignedName, ignoreEmptyStringLiteral)
|
||||
return factory.UpdateExportAssignment(
|
||||
node,
|
||||
nil, /*modifiers*/
|
||||
nil, /*typeNode*/
|
||||
expression,
|
||||
)
|
||||
}
|
||||
|
||||
// Performs a shallow transformation of a `NamedEvaluation` node, such that a valid name will be assigned.
|
||||
func transformNamedEvaluation(context *printer.EmitContext, node *ast.Node /*NamedEvaluation*/, ignoreEmptyStringLiteral bool, assignedName string) *ast.Expression {
|
||||
switch node.Kind {
|
||||
case ast.KindPropertyAssignment:
|
||||
return transformNamedEvaluationOfPropertyAssignment(context, node.AsPropertyAssignment(), ignoreEmptyStringLiteral, assignedName)
|
||||
case ast.KindShorthandPropertyAssignment:
|
||||
return transformNamedEvaluationOfShorthandAssignmentProperty(context, node.AsShorthandPropertyAssignment(), ignoreEmptyStringLiteral, assignedName)
|
||||
case ast.KindVariableDeclaration:
|
||||
return transformNamedEvaluationOfVariableDeclaration(context, node.AsVariableDeclaration(), ignoreEmptyStringLiteral, assignedName)
|
||||
case ast.KindParameter:
|
||||
return transformNamedEvaluationOfParameterDeclaration(context, node.AsParameterDeclaration(), ignoreEmptyStringLiteral, assignedName)
|
||||
case ast.KindBindingElement:
|
||||
return transformNamedEvaluationOfBindingElement(context, node.AsBindingElement(), ignoreEmptyStringLiteral, assignedName)
|
||||
case ast.KindPropertyDeclaration:
|
||||
return transformNamedEvaluationOfPropertyDeclaration(context, node.AsPropertyDeclaration(), ignoreEmptyStringLiteral, assignedName)
|
||||
case ast.KindBinaryExpression:
|
||||
return transformNamedEvaluationOfAssignmentExpression(context, node.AsBinaryExpression(), ignoreEmptyStringLiteral, assignedName)
|
||||
case ast.KindExportAssignment:
|
||||
return transformNamedEvaluationOfExportAssignment(context, node.AsExportAssignment(), ignoreEmptyStringLiteral, assignedName)
|
||||
default:
|
||||
panic("Unhandled case in transformNamedEvaluation")
|
||||
}
|
||||
}
|
||||
@ -1,49 +0,0 @@
|
||||
package estransforms
|
||||
|
||||
import (
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers"
|
||||
)
|
||||
|
||||
type nullishCoalescingTransformer struct {
|
||||
transformers.Transformer
|
||||
}
|
||||
|
||||
func (ch *nullishCoalescingTransformer) visit(node *ast.Node) *ast.Node {
|
||||
if node.SubtreeFacts()&ast.SubtreeContainsNullishCoalescing == 0 {
|
||||
return node
|
||||
}
|
||||
switch node.Kind {
|
||||
case ast.KindBinaryExpression:
|
||||
return ch.visitBinaryExpression(node.AsBinaryExpression())
|
||||
default:
|
||||
return ch.Visitor().VisitEachChild(node)
|
||||
}
|
||||
}
|
||||
|
||||
func (ch *nullishCoalescingTransformer) visitBinaryExpression(node *ast.BinaryExpression) *ast.Node {
|
||||
switch node.OperatorToken.Kind {
|
||||
case ast.KindQuestionQuestionToken:
|
||||
left := ch.Visitor().VisitNode(node.Left)
|
||||
right := left
|
||||
if !transformers.IsSimpleCopiableExpression(left) {
|
||||
right = ch.Factory().NewTempVariable()
|
||||
ch.EmitContext().AddVariableDeclaration(right)
|
||||
left = ch.Factory().NewAssignmentExpression(right, left)
|
||||
}
|
||||
return ch.Factory().NewConditionalExpression(
|
||||
createNotNullCondition(ch.EmitContext(), left, right, false),
|
||||
ch.Factory().NewToken(ast.KindQuestionToken),
|
||||
right,
|
||||
ch.Factory().NewToken(ast.KindColonToken),
|
||||
ch.Visitor().VisitNode(node.Right),
|
||||
)
|
||||
default:
|
||||
return ch.Visitor().VisitEachChild(node.AsNode())
|
||||
}
|
||||
}
|
||||
|
||||
func newNullishCoalescingTransformer(opts *transformers.TransformOptions) *transformers.Transformer {
|
||||
tx := &nullishCoalescingTransformer{}
|
||||
return tx.NewTransformer(tx.visit, opts.Context)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,37 +0,0 @@
|
||||
package estransforms
|
||||
|
||||
import (
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers"
|
||||
)
|
||||
|
||||
type optionalCatchTransformer struct {
|
||||
transformers.Transformer
|
||||
}
|
||||
|
||||
func (ch *optionalCatchTransformer) visit(node *ast.Node) *ast.Node {
|
||||
if node.SubtreeFacts()&ast.SubtreeContainsMissingCatchClauseVariable == 0 {
|
||||
return node
|
||||
}
|
||||
switch node.Kind {
|
||||
case ast.KindCatchClause:
|
||||
return ch.visitCatchClause(node.AsCatchClause())
|
||||
default:
|
||||
return ch.Visitor().VisitEachChild(node)
|
||||
}
|
||||
}
|
||||
|
||||
func (ch *optionalCatchTransformer) visitCatchClause(node *ast.CatchClause) *ast.Node {
|
||||
if node.VariableDeclaration == nil {
|
||||
return ch.Factory().NewCatchClause(
|
||||
ch.Factory().NewVariableDeclaration(ch.Factory().NewTempVariable(), nil, nil, nil),
|
||||
ch.Visitor().Visit(node.Block),
|
||||
)
|
||||
}
|
||||
return ch.Visitor().VisitEachChild(node.AsNode())
|
||||
}
|
||||
|
||||
func newOptionalCatchTransformer(opts *transformers.TransformOptions) *transformers.Transformer {
|
||||
tx := &optionalCatchTransformer{}
|
||||
return tx.NewTransformer(tx.visit, opts.Context)
|
||||
}
|
||||
@ -1,240 +0,0 @@
|
||||
package estransforms
|
||||
|
||||
import (
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/debug"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers"
|
||||
)
|
||||
|
||||
type optionalChainTransformer struct {
|
||||
transformers.Transformer
|
||||
}
|
||||
|
||||
func (ch *optionalChainTransformer) visit(node *ast.Node) *ast.Node {
|
||||
if node.SubtreeFacts()&ast.SubtreeContainsOptionalChaining == 0 {
|
||||
return node
|
||||
}
|
||||
switch node.Kind {
|
||||
case ast.KindCallExpression:
|
||||
return ch.visitCallExpression(node.AsCallExpression(), false)
|
||||
case ast.KindPropertyAccessExpression,
|
||||
ast.KindElementAccessExpression:
|
||||
if node.Flags&ast.NodeFlagsOptionalChain != 0 {
|
||||
return ch.visitOptionalExpression(node, false, false)
|
||||
}
|
||||
return ch.Visitor().VisitEachChild(node)
|
||||
case ast.KindDeleteExpression:
|
||||
return ch.visitDeleteExpression(node.AsDeleteExpression())
|
||||
default:
|
||||
return ch.Visitor().VisitEachChild(node)
|
||||
}
|
||||
}
|
||||
|
||||
func (ch *optionalChainTransformer) visitCallExpression(node *ast.CallExpression, captureThisArg bool) *ast.Node {
|
||||
if node.Flags&ast.NodeFlagsOptionalChain != 0 {
|
||||
// If `node` is an optional chain, then it is the outermost chain of an optional expression.
|
||||
return ch.visitOptionalExpression(node.AsNode(), captureThisArg, false)
|
||||
}
|
||||
if ast.IsParenthesizedExpression(node.Expression) {
|
||||
unwrapped := ast.SkipParentheses(node.Expression)
|
||||
if unwrapped.Flags&ast.NodeFlagsOptionalChain != 0 {
|
||||
// capture thisArg for calls of parenthesized optional chains like `(foo?.bar)()`
|
||||
expression := ch.visitParenthesizedExpression(node.Expression.AsParenthesizedExpression(), true, false)
|
||||
args := ch.Visitor().VisitNodes(node.Arguments)
|
||||
if ast.IsSyntheticReferenceExpression(expression) {
|
||||
res := ch.Factory().NewFunctionCallCall(expression.AsSyntheticReferenceExpression().Expression, expression.AsSyntheticReferenceExpression().ThisArg, args.Nodes)
|
||||
res.Loc = node.Loc
|
||||
ch.EmitContext().SetOriginal(res, node.AsNode())
|
||||
return res
|
||||
}
|
||||
return ch.Factory().UpdateCallExpression(node, expression, nil, nil, args)
|
||||
}
|
||||
}
|
||||
return ch.Visitor().VisitEachChild(node.AsNode())
|
||||
}
|
||||
|
||||
func (ch *optionalChainTransformer) visitParenthesizedExpression(node *ast.ParenthesizedExpression, captureThisArg bool, isDelete bool) *ast.Node {
|
||||
expr := ch.visitNonOptionalExpression(node.Expression, captureThisArg, isDelete)
|
||||
if ast.IsSyntheticReferenceExpression(expr) {
|
||||
// `(a.b)` -> { expression `((_a = a).b)`, thisArg: `_a` }
|
||||
// `(a[b])` -> { expression `((_a = a)[b])`, thisArg: `_a` }
|
||||
synth := expr.AsSyntheticReferenceExpression()
|
||||
res := ch.Factory().NewSyntheticReferenceExpression(ch.Factory().UpdateParenthesizedExpression(node, synth.Expression), synth.ThisArg)
|
||||
ch.EmitContext().SetOriginal(res, node.AsNode())
|
||||
return res
|
||||
}
|
||||
return ch.Factory().UpdateParenthesizedExpression(node, expr)
|
||||
}
|
||||
|
||||
func (ch *optionalChainTransformer) visitPropertyOrElementAccessExpression(node *ast.Expression, captureThisArg bool, isDelete bool) *ast.Expression {
|
||||
if node.Flags&ast.NodeFlagsOptionalChain != 0 {
|
||||
// If `node` is an optional chain, then it is the outermost chain of an optional expression.
|
||||
return ch.visitOptionalExpression(node.AsNode(), captureThisArg, isDelete)
|
||||
}
|
||||
expression := ch.Visitor().VisitNode(node.Expression())
|
||||
debug.AssertNotNode(expression, ast.IsSyntheticReferenceExpression)
|
||||
|
||||
var thisArg *ast.Expression
|
||||
if captureThisArg {
|
||||
if !transformers.IsSimpleCopiableExpression(expression) {
|
||||
thisArg = ch.Factory().NewTempVariable()
|
||||
ch.EmitContext().AddVariableDeclaration(thisArg)
|
||||
expression = ch.Factory().NewAssignmentExpression(thisArg, expression)
|
||||
} else {
|
||||
thisArg = expression
|
||||
}
|
||||
}
|
||||
|
||||
if node.Kind == ast.KindPropertyAccessExpression {
|
||||
p := node.AsPropertyAccessExpression()
|
||||
expression = ch.Factory().UpdatePropertyAccessExpression(p, expression, nil, ch.Visitor().VisitNode(p.Name()))
|
||||
} else {
|
||||
p := node.AsElementAccessExpression()
|
||||
expression = ch.Factory().UpdateElementAccessExpression(p, expression, nil, ch.Visitor().VisitNode(p.AsElementAccessExpression().ArgumentExpression))
|
||||
}
|
||||
|
||||
if thisArg != nil {
|
||||
res := ch.Factory().NewSyntheticReferenceExpression(expression, thisArg)
|
||||
ch.EmitContext().SetOriginal(res, node.AsNode())
|
||||
return res
|
||||
}
|
||||
return expression
|
||||
}
|
||||
|
||||
func (ch *optionalChainTransformer) visitDeleteExpression(node *ast.DeleteExpression) *ast.Node {
|
||||
unwrapped := ast.SkipParentheses(node.Expression)
|
||||
if unwrapped.Flags&ast.NodeFlagsOptionalChain != 0 {
|
||||
return ch.visitNonOptionalExpression(node.Expression, false, true)
|
||||
}
|
||||
return ch.Visitor().VisitEachChild(node.AsNode())
|
||||
}
|
||||
|
||||
func (ch *optionalChainTransformer) visitNonOptionalExpression(node *ast.Expression, captureThisArg bool, isDelete bool) *ast.Expression {
|
||||
switch node.Kind {
|
||||
case ast.KindParenthesizedExpression:
|
||||
return ch.visitParenthesizedExpression(node.AsParenthesizedExpression(), captureThisArg, isDelete)
|
||||
case ast.KindElementAccessExpression, ast.KindPropertyAccessExpression:
|
||||
return ch.visitPropertyOrElementAccessExpression(node, captureThisArg, isDelete)
|
||||
case ast.KindCallExpression:
|
||||
return ch.visitCallExpression(node.AsCallExpression(), captureThisArg)
|
||||
default:
|
||||
return ch.Visitor().VisitNode(node.AsNode())
|
||||
}
|
||||
}
|
||||
|
||||
type flattenResult struct {
|
||||
expression *ast.Expression
|
||||
chain []*ast.Node
|
||||
}
|
||||
|
||||
func isNonNullChain(node *ast.Node) bool {
|
||||
return ast.IsNonNullExpression(node) && node.Flags&ast.NodeFlagsOptionalChain != 0
|
||||
}
|
||||
|
||||
func flattenChain(chain *ast.Node) flattenResult {
|
||||
debug.AssertNotNode(chain, isNonNullChain)
|
||||
links := []*ast.Node{chain}
|
||||
for !ast.IsTaggedTemplateExpression(chain) && chain.QuestionDotToken() == nil {
|
||||
chain = ast.SkipPartiallyEmittedExpressions(chain.Expression())
|
||||
debug.AssertNotNode(chain, isNonNullChain)
|
||||
links = append([]*ast.Node{chain}, links...)
|
||||
}
|
||||
return flattenResult{chain.Expression(), links}
|
||||
}
|
||||
|
||||
func isCallChain(node *ast.Node) bool {
|
||||
return ast.IsCallExpression(node) && node.Flags&ast.NodeFlagsOptionalChain != 0
|
||||
}
|
||||
|
||||
func (ch *optionalChainTransformer) visitOptionalExpression(node *ast.Node, captureThisArg bool, isDelete bool) *ast.Node {
|
||||
r := flattenChain(node)
|
||||
expression := r.expression
|
||||
chain := r.chain
|
||||
left := ch.visitNonOptionalExpression(ast.SkipPartiallyEmittedExpressions(expression), isCallChain(chain[0]), false)
|
||||
var leftThisArg *ast.Expression
|
||||
capturedLeft := left
|
||||
if ast.IsSyntheticReferenceExpression(left) {
|
||||
leftThisArg = left.AsSyntheticReferenceExpression().ThisArg
|
||||
capturedLeft = left.AsSyntheticReferenceExpression().Expression
|
||||
}
|
||||
leftExpression := ch.Factory().RestoreOuterExpressions(expression, capturedLeft, ast.OEKPartiallyEmittedExpressions)
|
||||
if !transformers.IsSimpleCopiableExpression(capturedLeft) {
|
||||
capturedLeft = ch.Factory().NewTempVariable()
|
||||
ch.EmitContext().AddVariableDeclaration(capturedLeft)
|
||||
leftExpression = ch.Factory().NewAssignmentExpression(capturedLeft, leftExpression)
|
||||
}
|
||||
rightExpression := capturedLeft
|
||||
var thisArg *ast.Expression
|
||||
|
||||
for i, segment := range chain {
|
||||
switch segment.Kind {
|
||||
case ast.KindElementAccessExpression, ast.KindPropertyAccessExpression:
|
||||
if i == len(chain)-1 && captureThisArg {
|
||||
if !transformers.IsSimpleCopiableExpression(rightExpression) {
|
||||
thisArg = ch.Factory().NewTempVariable()
|
||||
ch.EmitContext().AddVariableDeclaration(thisArg)
|
||||
rightExpression = ch.Factory().NewAssignmentExpression(thisArg, rightExpression)
|
||||
} else {
|
||||
thisArg = rightExpression
|
||||
}
|
||||
}
|
||||
if segment.Kind == ast.KindElementAccessExpression {
|
||||
rightExpression = ch.Factory().NewElementAccessExpression(rightExpression, nil, ch.Visitor().VisitNode(segment.AsElementAccessExpression().ArgumentExpression), ast.NodeFlagsNone)
|
||||
} else {
|
||||
rightExpression = ch.Factory().NewPropertyAccessExpression(rightExpression, nil, ch.Visitor().VisitNode(segment.AsPropertyAccessExpression().Name()), ast.NodeFlagsNone)
|
||||
}
|
||||
case ast.KindCallExpression:
|
||||
if i == 0 && leftThisArg != nil {
|
||||
if !ch.EmitContext().HasAutoGenerateInfo(leftThisArg) {
|
||||
leftThisArg = leftThisArg.Clone(ch.Factory())
|
||||
ch.EmitContext().AddEmitFlags(leftThisArg, printer.EFNoComments)
|
||||
}
|
||||
callThisArg := leftThisArg
|
||||
if leftThisArg.Kind == ast.KindSuperKeyword {
|
||||
callThisArg = ch.Factory().NewThisExpression()
|
||||
}
|
||||
rightExpression = ch.Factory().NewFunctionCallCall(rightExpression, callThisArg, ch.Visitor().VisitNodes(segment.ArgumentList()).Nodes)
|
||||
} else {
|
||||
rightExpression = ch.Factory().NewCallExpression(
|
||||
rightExpression,
|
||||
nil,
|
||||
nil,
|
||||
ch.Visitor().VisitNodes(segment.ArgumentList()),
|
||||
ast.NodeFlagsNone,
|
||||
)
|
||||
}
|
||||
}
|
||||
ch.EmitContext().SetOriginal(rightExpression, segment)
|
||||
}
|
||||
|
||||
var target *ast.Node
|
||||
if isDelete {
|
||||
target = ch.Factory().NewConditionalExpression(
|
||||
createNotNullCondition(ch.EmitContext(), leftExpression, capturedLeft, true),
|
||||
ch.Factory().NewToken(ast.KindQuestionToken),
|
||||
ch.Factory().NewTrueExpression(),
|
||||
ch.Factory().NewToken(ast.KindColonToken),
|
||||
ch.Factory().NewDeleteExpression(rightExpression),
|
||||
)
|
||||
} else {
|
||||
target = ch.Factory().NewConditionalExpression(
|
||||
createNotNullCondition(ch.EmitContext(), leftExpression, capturedLeft, true),
|
||||
ch.Factory().NewToken(ast.KindQuestionToken),
|
||||
ch.Factory().NewVoidZeroExpression(),
|
||||
ch.Factory().NewToken(ast.KindColonToken),
|
||||
rightExpression,
|
||||
)
|
||||
}
|
||||
target.Loc = node.Loc
|
||||
if thisArg != nil {
|
||||
target = ch.Factory().NewSyntheticReferenceExpression(target, thisArg)
|
||||
}
|
||||
ch.EmitContext().SetOriginal(target, node.AsNode())
|
||||
return target
|
||||
}
|
||||
|
||||
func newOptionalChainTransformer(opts *transformers.TransformOptions) *transformers.Transformer {
|
||||
tx := &optionalChainTransformer{}
|
||||
return tx.NewTransformer(tx.visit, opts.Context)
|
||||
}
|
||||
@ -1,867 +0,0 @@
|
||||
package estransforms
|
||||
|
||||
import (
|
||||
"maps"
|
||||
"slices"
|
||||
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers"
|
||||
)
|
||||
|
||||
type usingDeclarationTransformer struct {
|
||||
transformers.Transformer
|
||||
|
||||
exportBindings map[string]*ast.ExportSpecifierNode
|
||||
exportVars []*ast.VariableDeclarationNode
|
||||
defaultExportBinding *ast.IdentifierNode
|
||||
exportEqualsBinding *ast.IdentifierNode
|
||||
}
|
||||
|
||||
func newUsingDeclarationTransformer(opts *transformers.TransformOptions) *transformers.Transformer {
|
||||
tx := &usingDeclarationTransformer{}
|
||||
return tx.NewTransformer(tx.visit, opts.Context)
|
||||
}
|
||||
|
||||
type usingKind uint
|
||||
|
||||
const (
|
||||
usingKindNone usingKind = iota
|
||||
usingKindSync
|
||||
usingKindAsync
|
||||
)
|
||||
|
||||
func (tx *usingDeclarationTransformer) visit(node *ast.Node) *ast.Node {
|
||||
if node.SubtreeFacts()&ast.SubtreeContainsUsing == 0 {
|
||||
return node
|
||||
}
|
||||
|
||||
switch node.Kind {
|
||||
case ast.KindSourceFile:
|
||||
node = tx.visitSourceFile(node.AsSourceFile())
|
||||
case ast.KindBlock:
|
||||
node = tx.visitBlock(node.AsBlock())
|
||||
case ast.KindForStatement:
|
||||
node = tx.visitForStatement(node.AsForStatement())
|
||||
case ast.KindForOfStatement:
|
||||
node = tx.visitForOfStatement(node.AsForInOrOfStatement())
|
||||
case ast.KindSwitchStatement:
|
||||
node = tx.visitSwitchStatement(node.AsSwitchStatement())
|
||||
default:
|
||||
node = tx.Visitor().VisitEachChild(node)
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
func (tx *usingDeclarationTransformer) visitSourceFile(node *ast.SourceFile) *ast.Node {
|
||||
if node.IsDeclarationFile {
|
||||
return node.AsNode()
|
||||
}
|
||||
|
||||
var visited *ast.SourceFileNode
|
||||
usingKind := getUsingKindOfStatements(node.Statements.Nodes)
|
||||
if usingKind != usingKindNone {
|
||||
// Imports and exports must stay at the top level. This means we must hoist all imports, exports, and
|
||||
// top-level function declarations and bindings out of the `try` statements we generate. For example:
|
||||
//
|
||||
// given:
|
||||
//
|
||||
// import { w } from "mod";
|
||||
// const x = expr1;
|
||||
// using y = expr2;
|
||||
// const z = expr3;
|
||||
// export function f() {
|
||||
// console.log(z);
|
||||
// }
|
||||
//
|
||||
// produces:
|
||||
//
|
||||
// import { x } from "mod"; // <-- preserved
|
||||
// const x = expr1; // <-- preserved
|
||||
// var y, z; // <-- hoisted
|
||||
// export function f() { // <-- hoisted
|
||||
// console.log(z);
|
||||
// }
|
||||
// const env_1 = { stack: [], error: void 0, hasError: false };
|
||||
// try {
|
||||
// y = __addDisposableResource(env_1, expr2, false);
|
||||
// z = expr3;
|
||||
// }
|
||||
// catch (e_1) {
|
||||
// env_1.error = e_1;
|
||||
// env_1.hasError = true;
|
||||
// }
|
||||
// finally {
|
||||
// __disposeResource(env_1);
|
||||
// }
|
||||
//
|
||||
// In this transformation, we hoist `y`, `z`, and `f` to a new outer statement list while moving all other
|
||||
// statements in the source file into the `try` block, which is the same approach we use for System module
|
||||
// emit. Unlike System module emit, we attempt to preserve all statements prior to the first top-level
|
||||
// `using` to isolate the complexity of the transformed output to only where it is necessary.
|
||||
tx.EmitContext().StartVariableEnvironment()
|
||||
|
||||
tx.exportBindings = make(map[string]*ast.ExportSpecifierNode)
|
||||
tx.exportVars = nil
|
||||
|
||||
prologue, rest := tx.Factory().SplitStandardPrologue(node.Statements.Nodes)
|
||||
var topLevelStatements []*ast.Statement
|
||||
topLevelStatements = append(topLevelStatements, core.FirstResult(tx.Visitor().VisitSlice(prologue))...)
|
||||
|
||||
// Collect and transform any leading statements up to the first `using` or `await using`. This preserves
|
||||
// the original statement order much as is possible.
|
||||
|
||||
pos := 0
|
||||
for pos < len(rest) {
|
||||
statement := rest[pos]
|
||||
if getUsingKind(statement) != usingKindNone {
|
||||
if pos > 0 {
|
||||
topLevelStatements = append(topLevelStatements, core.FirstResult(tx.Visitor().VisitSlice(rest[:pos]))...)
|
||||
}
|
||||
break
|
||||
}
|
||||
pos++
|
||||
}
|
||||
|
||||
if pos >= len(rest) {
|
||||
panic("Should have encountered at least one 'using' statement.")
|
||||
}
|
||||
|
||||
// transform the rest of the body
|
||||
envBinding := tx.createEnvBinding()
|
||||
bodyStatements := tx.transformUsingDeclarations(rest[pos:], envBinding, &topLevelStatements)
|
||||
|
||||
// add `export {}` declarations for any hoisted bindings.
|
||||
if len(tx.exportBindings) > 0 {
|
||||
topLevelStatements = append(
|
||||
topLevelStatements,
|
||||
tx.Factory().NewExportDeclaration(
|
||||
nil, /*modifiers*/
|
||||
false, /*isTypeOnly*/
|
||||
tx.Factory().NewNamedExports(
|
||||
tx.Factory().NewNodeList(
|
||||
slices.Collect(maps.Values(tx.exportBindings)),
|
||||
),
|
||||
),
|
||||
nil, /*moduleSpecifier*/
|
||||
nil, /*attributes*/
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
topLevelStatements = tx.EmitContext().EndAndMergeVariableEnvironment(topLevelStatements)
|
||||
if len(tx.exportVars) > 0 {
|
||||
topLevelStatements = append(topLevelStatements, tx.Factory().NewVariableStatement(
|
||||
tx.Factory().NewModifierList([]*ast.Node{
|
||||
tx.Factory().NewModifier(ast.KindExportKeyword),
|
||||
}),
|
||||
tx.Factory().NewVariableDeclarationList(
|
||||
ast.NodeFlagsLet,
|
||||
tx.Factory().NewNodeList(tx.exportVars),
|
||||
),
|
||||
))
|
||||
}
|
||||
topLevelStatements = append(topLevelStatements, tx.createDownlevelUsingStatements(bodyStatements, envBinding, usingKind == usingKindAsync)...)
|
||||
|
||||
if tx.exportEqualsBinding != nil {
|
||||
topLevelStatements = append(topLevelStatements, tx.Factory().NewExportAssignment(
|
||||
nil, /*modifiers*/
|
||||
true, /*isExportEquals*/
|
||||
nil, /*typeNode*/
|
||||
tx.exportEqualsBinding,
|
||||
))
|
||||
}
|
||||
|
||||
visited = tx.Factory().UpdateSourceFile(node, tx.Factory().NewNodeList(topLevelStatements), node.EndOfFileToken)
|
||||
} else {
|
||||
visited = tx.Visitor().VisitEachChild(node.AsNode())
|
||||
}
|
||||
tx.EmitContext().AddEmitHelper(visited, tx.EmitContext().ReadEmitHelpers()...)
|
||||
tx.exportVars = nil
|
||||
tx.exportBindings = nil
|
||||
tx.defaultExportBinding = nil
|
||||
tx.exportEqualsBinding = nil
|
||||
return visited
|
||||
}
|
||||
|
||||
func (tx *usingDeclarationTransformer) visitBlock(node *ast.Block) *ast.Node {
|
||||
usingKind := getUsingKindOfStatements(node.Statements.Nodes)
|
||||
if usingKind != usingKindNone {
|
||||
prologue, rest := tx.Factory().SplitStandardPrologue(node.Statements.Nodes)
|
||||
envBinding := tx.createEnvBinding()
|
||||
statements := make([]*ast.Statement, 0, len(prologue)+2)
|
||||
statements = append(statements, core.FirstResult(tx.Visitor().VisitSlice(prologue))...)
|
||||
statements = append(statements, tx.createDownlevelUsingStatements(
|
||||
tx.transformUsingDeclarations(rest, envBinding, nil /*topLevelStatements*/),
|
||||
envBinding,
|
||||
usingKind == usingKindAsync,
|
||||
)...)
|
||||
statementList := tx.Factory().NewNodeList(statements)
|
||||
statementList.Loc = node.Statements.Loc
|
||||
return tx.Factory().UpdateBlock(node, statementList)
|
||||
}
|
||||
return tx.Visitor().VisitEachChild(node.AsNode())
|
||||
}
|
||||
|
||||
func (tx *usingDeclarationTransformer) visitForStatement(node *ast.ForStatement) *ast.Node {
|
||||
if node.Initializer != nil && isUsingVariableDeclarationList(node.Initializer) {
|
||||
// given:
|
||||
//
|
||||
// for (using x = expr; cond; incr) { ... }
|
||||
//
|
||||
// produces a shallow transformation to:
|
||||
//
|
||||
// {
|
||||
// using x = expr;
|
||||
// for (; cond; incr) { ... }
|
||||
// }
|
||||
//
|
||||
// before handing the shallow transformation back to the visitor for an in-depth transformation.
|
||||
return tx.Visitor().VisitNode(
|
||||
tx.Factory().NewBlock(tx.Factory().NewNodeList([]*ast.Statement{
|
||||
tx.Factory().NewVariableStatement(nil /*modifiers*/, node.Initializer),
|
||||
tx.Factory().UpdateForStatement(
|
||||
node,
|
||||
nil, /*initializer*/
|
||||
node.Condition,
|
||||
node.Incrementor,
|
||||
node.Statement,
|
||||
),
|
||||
}), false /*multiLine*/),
|
||||
)
|
||||
}
|
||||
return tx.Visitor().VisitEachChild(node.AsNode())
|
||||
}
|
||||
|
||||
func (tx *usingDeclarationTransformer) visitForOfStatement(node *ast.ForInOrOfStatement) *ast.Node {
|
||||
if isUsingVariableDeclarationList(node.Initializer) {
|
||||
// given:
|
||||
//
|
||||
// for (using x of y) { ... }
|
||||
//
|
||||
// produces a shallow transformation to:
|
||||
//
|
||||
// for (const x_1 of y) {
|
||||
// using x = x;
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// before handing the shallow transformation back to the visitor for an in-depth transformation.
|
||||
forInitializer := node.Initializer.AsVariableDeclarationList()
|
||||
forDecl := core.FirstOrNil(forInitializer.Declarations.Nodes)
|
||||
if forDecl == nil {
|
||||
forDecl = tx.Factory().NewVariableDeclaration(tx.Factory().NewTempVariable(), nil, nil, nil)
|
||||
}
|
||||
|
||||
isAwaitUsing := getUsingKindOfVariableDeclarationList(forInitializer) == usingKindAsync
|
||||
temp := tx.Factory().NewGeneratedNameForNode(forDecl.Name())
|
||||
usingVar := tx.Factory().UpdateVariableDeclaration(forDecl.AsVariableDeclaration(), forDecl.Name(), nil /*exclamationToken*/, nil /*type*/, temp)
|
||||
usingVarList := tx.Factory().NewVariableDeclarationList(
|
||||
core.IfElse(isAwaitUsing, ast.NodeFlagsAwaitUsing, ast.NodeFlagsUsing),
|
||||
tx.Factory().NewNodeList([]*ast.Node{usingVar}),
|
||||
)
|
||||
usingVarStatement := tx.Factory().NewVariableStatement(nil /*modifiers*/, usingVarList)
|
||||
var statement *ast.Statement
|
||||
if ast.IsBlock(node.Statement) {
|
||||
statements := make([]*ast.Statement, 0, len(node.Statement.AsBlock().Statements.Nodes)+1)
|
||||
statements = append(statements, usingVarStatement)
|
||||
statements = append(statements, node.Statement.AsBlock().Statements.Nodes...)
|
||||
statement = tx.Factory().UpdateBlock(
|
||||
node.Statement.AsBlock(),
|
||||
tx.Factory().NewNodeList(statements),
|
||||
)
|
||||
} else {
|
||||
statement = tx.Factory().NewBlock(
|
||||
tx.Factory().NewNodeList([]*ast.Statement{
|
||||
usingVarStatement,
|
||||
node.Statement,
|
||||
}),
|
||||
true, /*multiLine*/
|
||||
)
|
||||
}
|
||||
return tx.Visitor().VisitNode(
|
||||
tx.Factory().UpdateForInOrOfStatement(
|
||||
node,
|
||||
node.AwaitModifier,
|
||||
tx.Factory().NewVariableDeclarationList(
|
||||
ast.NodeFlagsConst,
|
||||
tx.Factory().NewNodeList([]*ast.VariableDeclarationNode{
|
||||
tx.Factory().NewVariableDeclaration(temp, nil /*exclamationToken*/, nil /*type*/, nil),
|
||||
}),
|
||||
),
|
||||
node.Expression,
|
||||
statement,
|
||||
),
|
||||
)
|
||||
}
|
||||
return tx.Visitor().VisitEachChild(node.AsNode())
|
||||
}
|
||||
|
||||
func (tx *usingDeclarationTransformer) visitCaseOrDefaultClause(node *ast.CaseOrDefaultClause, envBinding *ast.IdentifierNode) *ast.Node {
|
||||
if getUsingKindOfStatements(node.Statements.Nodes) != usingKindNone {
|
||||
return tx.Factory().UpdateCaseOrDefaultClause(
|
||||
node,
|
||||
tx.Visitor().VisitNode(node.Expression),
|
||||
tx.Factory().NewNodeList(tx.transformUsingDeclarations(node.Statements.Nodes, envBinding, nil /*topLevelStatements*/)),
|
||||
)
|
||||
}
|
||||
return tx.Visitor().VisitEachChild(node.AsNode())
|
||||
}
|
||||
|
||||
func (tx *usingDeclarationTransformer) visitSwitchStatement(node *ast.SwitchStatement) *ast.Node {
|
||||
// given:
|
||||
//
|
||||
// switch (expr) {
|
||||
// case expr:
|
||||
// using res = expr;
|
||||
// }
|
||||
//
|
||||
// produces:
|
||||
//
|
||||
// const env_1 = { stack: [], error: void 0, hasError: false };
|
||||
// try {
|
||||
// switch(expr) {
|
||||
// case expr:
|
||||
// const res = __addDisposableResource(env_1, expr, false);
|
||||
// }
|
||||
// }
|
||||
// catch (e_1) {
|
||||
// env_1.error = e_1;
|
||||
// env_1.hasError = true;
|
||||
// }
|
||||
// finally {
|
||||
// __disposeResources(env_1);
|
||||
// }
|
||||
//
|
||||
usingKind := getUsingKindOfCaseOrDefaultClauses(node.CaseBlock.AsCaseBlock().Clauses.Nodes)
|
||||
if usingKind != usingKindNone {
|
||||
envBinding := tx.createEnvBinding()
|
||||
return transformers.SingleOrMany(tx.createDownlevelUsingStatements(
|
||||
[]*ast.Statement{
|
||||
tx.Factory().UpdateSwitchStatement(
|
||||
node,
|
||||
tx.Visitor().VisitNode(node.Expression),
|
||||
tx.Factory().UpdateCaseBlock(
|
||||
node.CaseBlock.AsCaseBlock(),
|
||||
tx.Factory().NewNodeList(
|
||||
core.Map(node.CaseBlock.AsCaseBlock().Clauses.Nodes, func(clause *ast.CaseOrDefaultClauseNode) *ast.CaseOrDefaultClauseNode {
|
||||
return tx.visitCaseOrDefaultClause(clause.AsCaseOrDefaultClause(), envBinding)
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
envBinding,
|
||||
usingKind == usingKindAsync,
|
||||
), tx.Factory())
|
||||
}
|
||||
|
||||
return tx.Visitor().VisitEachChild(node.AsNode())
|
||||
}
|
||||
|
||||
func (tx *usingDeclarationTransformer) transformUsingDeclarations(statementsIn []*ast.Statement, envBinding *ast.IdentifierNode, topLevelStatements *[]*ast.Statement) []*ast.Node {
|
||||
var statements []*ast.Statement
|
||||
|
||||
hoist := func(node *ast.Statement) *ast.Statement {
|
||||
if topLevelStatements == nil {
|
||||
return node
|
||||
}
|
||||
|
||||
switch node.Kind {
|
||||
case ast.KindImportDeclaration,
|
||||
ast.KindImportEqualsDeclaration,
|
||||
ast.KindExportDeclaration,
|
||||
ast.KindFunctionDeclaration:
|
||||
tx.hoistImportOrExportOrHoistedDeclaration(node, topLevelStatements)
|
||||
return nil
|
||||
case ast.KindExportAssignment:
|
||||
return tx.hoistExportAssignment(node.AsExportAssignment())
|
||||
case ast.KindClassDeclaration:
|
||||
return tx.hoistClassDeclaration(node.AsClassDeclaration())
|
||||
case ast.KindVariableStatement:
|
||||
return tx.hoistVariableStatement(node.AsVariableStatement())
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
hoistOrAppendNode := func(node *ast.Node) {
|
||||
node = hoist(node)
|
||||
if node != nil {
|
||||
statements = append(statements, node)
|
||||
}
|
||||
}
|
||||
|
||||
for _, statement := range statementsIn {
|
||||
usingKind := getUsingKind(statement)
|
||||
if usingKind != usingKindNone {
|
||||
varStatement := statement.AsVariableStatement()
|
||||
declarationList := varStatement.DeclarationList
|
||||
var declarations []*ast.VariableDeclarationNode
|
||||
for _, declaration := range declarationList.AsVariableDeclarationList().Declarations.Nodes {
|
||||
if !ast.IsIdentifier(declaration.Name()) {
|
||||
// Since binding patterns are a grammar error, we reset `declarations` so we don't process this as a `using`.
|
||||
declarations = nil
|
||||
break
|
||||
}
|
||||
|
||||
// perform a shallow transform for any named evaluation
|
||||
if isNamedEvaluation(tx.EmitContext(), declaration) {
|
||||
declaration = transformNamedEvaluation(tx.EmitContext(), declaration, false /*ignoreEmptyStringLiteral*/, "" /*assignedName*/)
|
||||
}
|
||||
|
||||
initializer := tx.Visitor().VisitNode(declaration.Initializer())
|
||||
if initializer == nil {
|
||||
initializer = tx.Factory().NewVoidZeroExpression()
|
||||
}
|
||||
declarations = append(declarations, tx.Factory().UpdateVariableDeclaration(
|
||||
declaration.AsVariableDeclaration(),
|
||||
declaration.Name(),
|
||||
nil, /*exclamationToken*/
|
||||
nil, /*type*/
|
||||
tx.Factory().NewAddDisposableResourceHelper(
|
||||
envBinding,
|
||||
initializer,
|
||||
usingKind == usingKindAsync,
|
||||
),
|
||||
))
|
||||
}
|
||||
|
||||
// Only replace the statement if it was valid.
|
||||
if len(declarations) > 0 {
|
||||
varList := tx.Factory().NewVariableDeclarationList(ast.NodeFlagsConst, tx.Factory().NewNodeList(declarations))
|
||||
tx.EmitContext().SetOriginal(varList, declarationList)
|
||||
varList.Loc = declarationList.Loc
|
||||
hoistOrAppendNode(tx.Factory().UpdateVariableStatement(varStatement, nil /*modifiers*/, varList))
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if result := tx.visit(statement); result != nil {
|
||||
if result.Kind == ast.KindSyntaxList {
|
||||
for _, node := range result.AsSyntaxList().Children {
|
||||
hoistOrAppendNode(node)
|
||||
}
|
||||
} else {
|
||||
hoistOrAppendNode(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
return statements
|
||||
}
|
||||
|
||||
func (tx *usingDeclarationTransformer) hoistImportOrExportOrHoistedDeclaration(node *ast.Statement, topLevelStatements *[]*ast.Statement) {
|
||||
// NOTE: `node` has already been visited
|
||||
*topLevelStatements = append(*topLevelStatements, node)
|
||||
}
|
||||
|
||||
func (tx *usingDeclarationTransformer) hoistExportAssignment(node *ast.ExportAssignment) *ast.Statement {
|
||||
if node.IsExportEquals {
|
||||
return tx.hoistExportEquals(node)
|
||||
} else {
|
||||
return tx.hoistExportDefault(node)
|
||||
}
|
||||
}
|
||||
|
||||
func (tx *usingDeclarationTransformer) hoistExportDefault(node *ast.ExportAssignment) *ast.Statement {
|
||||
// NOTE: `node` has already been visited
|
||||
if tx.defaultExportBinding != nil {
|
||||
// invalid case of multiple `export default` declarations. Don't assert here, just pass it through
|
||||
return node.AsNode()
|
||||
}
|
||||
|
||||
// given:
|
||||
//
|
||||
// export default expr;
|
||||
//
|
||||
// produces:
|
||||
//
|
||||
// // top level
|
||||
// var default_1;
|
||||
// export { default_1 as default };
|
||||
//
|
||||
// // body
|
||||
// default_1 = expr;
|
||||
|
||||
tx.defaultExportBinding = tx.Factory().NewUniqueNameEx("_default", printer.AutoGenerateOptions{Flags: printer.GeneratedIdentifierFlagsReservedInNestedScopes | printer.GeneratedIdentifierFlagsFileLevel | printer.GeneratedIdentifierFlagsOptimistic})
|
||||
tx.hoistBindingIdentifier(tx.defaultExportBinding /*isExport*/, true, tx.Factory().NewIdentifier("default"), node.AsNode())
|
||||
|
||||
// give a class or function expression an assigned name, if needed.
|
||||
expression := node.Expression
|
||||
innerExpression := ast.SkipOuterExpressions(expression, ast.OEKAll)
|
||||
if isNamedEvaluation(tx.EmitContext(), innerExpression) {
|
||||
innerExpression = transformNamedEvaluation(tx.EmitContext(), innerExpression /*ignoreEmptyStringLiteral*/, false, "default")
|
||||
expression = tx.Factory().RestoreOuterExpressions(expression, innerExpression, ast.OEKAll)
|
||||
}
|
||||
|
||||
assignment := tx.Factory().NewAssignmentExpression(tx.defaultExportBinding, expression)
|
||||
return tx.Factory().NewExpressionStatement(assignment)
|
||||
}
|
||||
|
||||
func (tx *usingDeclarationTransformer) hoistExportEquals(node *ast.ExportAssignment) *ast.Statement {
|
||||
// NOTE: `node` has already been visited
|
||||
if tx.exportEqualsBinding != nil {
|
||||
// invalid case of multiple `export default` declarations. Don't assert here, just pass it through
|
||||
return node.AsNode()
|
||||
}
|
||||
|
||||
// given:
|
||||
//
|
||||
// export = expr;
|
||||
//
|
||||
// produces:
|
||||
//
|
||||
// // top level
|
||||
// var default_1;
|
||||
//
|
||||
// try {
|
||||
// // body
|
||||
// default_1 = expr;
|
||||
// } ...
|
||||
//
|
||||
// // top level suffix
|
||||
// export = default_1;
|
||||
|
||||
tx.exportEqualsBinding = tx.Factory().NewUniqueNameEx("_default", printer.AutoGenerateOptions{Flags: printer.GeneratedIdentifierFlagsReservedInNestedScopes | printer.GeneratedIdentifierFlagsFileLevel | printer.GeneratedIdentifierFlagsOptimistic})
|
||||
tx.EmitContext().AddVariableDeclaration(tx.exportEqualsBinding)
|
||||
|
||||
// give a class or function expression an assigned name, if needed.
|
||||
assignment := tx.Factory().NewAssignmentExpression(tx.exportEqualsBinding, node.Expression)
|
||||
return tx.Factory().NewExpressionStatement(assignment)
|
||||
}
|
||||
|
||||
func (tx *usingDeclarationTransformer) hoistClassDeclaration(node *ast.ClassDeclaration) *ast.Statement {
|
||||
// NOTE: `node` has already been visited
|
||||
if node.Name() == nil && tx.defaultExportBinding != nil {
|
||||
// invalid case of multiple `export default` declarations. Don't assert here, just pass it through
|
||||
return node.AsNode()
|
||||
}
|
||||
|
||||
isExported := ast.HasSyntacticModifier(node.AsNode(), ast.ModifierFlagsExport)
|
||||
isDefault := ast.HasSyntacticModifier(node.AsNode(), ast.ModifierFlagsDefault)
|
||||
|
||||
// When hoisting a class declaration at the top level of a file containing a top-level `using` statement, we
|
||||
// must first convert it to a class expression so that we can hoist the binding outside of the `try`.
|
||||
expression := convertClassDeclarationToClassExpression(tx.EmitContext(), node)
|
||||
if node.Name() != nil {
|
||||
// given:
|
||||
//
|
||||
// using x = expr;
|
||||
// class C {}
|
||||
//
|
||||
// produces:
|
||||
//
|
||||
// var x, C;
|
||||
// const env_1 = { ... };
|
||||
// try {
|
||||
// x = __addDisposableResource(env_1, expr, false);
|
||||
// C = class {};
|
||||
// }
|
||||
// catch (e_1) {
|
||||
// env_1.error = e_1;
|
||||
// env_1.hasError = true;
|
||||
// }
|
||||
// finally {
|
||||
// __disposeResources(env_1);
|
||||
// }
|
||||
//
|
||||
// If the class is exported, we also produce an `export { C };`
|
||||
tx.hoistBindingIdentifier(tx.Factory().GetLocalName(node.AsNode()), isExported && !isDefault, nil /*exportAlias*/, node.AsNode())
|
||||
expression = tx.Factory().NewAssignmentExpression(tx.Factory().GetDeclarationName(node.AsNode()), expression)
|
||||
tx.EmitContext().SetOriginal(expression, node.AsNode())
|
||||
tx.EmitContext().SetSourceMapRange(expression, node.Loc)
|
||||
tx.EmitContext().SetCommentRange(expression, node.Loc)
|
||||
if isNamedEvaluation(tx.EmitContext(), expression) {
|
||||
expression = transformNamedEvaluation(tx.EmitContext(), expression, false /*ignoreEmptyStringLiteral*/, "" /*assignedName*/)
|
||||
}
|
||||
}
|
||||
|
||||
if isDefault && tx.defaultExportBinding == nil {
|
||||
// In the case of a default export, we create a temporary variable that we export as the default and then
|
||||
// assign to that variable.
|
||||
//
|
||||
// given:
|
||||
//
|
||||
// using x = expr;
|
||||
// export default class C {}
|
||||
//
|
||||
// produces:
|
||||
//
|
||||
// export { default_1 as default };
|
||||
// var x, C, default_1;
|
||||
// const env_1 = { ... };
|
||||
// try {
|
||||
// x = __addDisposableResource(env_1, expr, false);
|
||||
// default_1 = C = class {};
|
||||
// }
|
||||
// catch (e_1) {
|
||||
// env_1.error = e_1;
|
||||
// env_1.hasError = true;
|
||||
// }
|
||||
// finally {
|
||||
// __disposeResources(env_1);
|
||||
// }
|
||||
//
|
||||
// Though we will never reassign `default_1`, this most closely matches the specified runtime semantics.
|
||||
tx.defaultExportBinding = tx.Factory().NewUniqueNameEx("_default", printer.AutoGenerateOptions{Flags: printer.GeneratedIdentifierFlagsReservedInNestedScopes | printer.GeneratedIdentifierFlagsFileLevel | printer.GeneratedIdentifierFlagsOptimistic})
|
||||
tx.hoistBindingIdentifier(tx.defaultExportBinding /*isExport*/, true, tx.Factory().NewIdentifier("default"), node.AsNode())
|
||||
expression = tx.Factory().NewAssignmentExpression(tx.defaultExportBinding, expression)
|
||||
tx.EmitContext().SetOriginal(expression, node.AsNode())
|
||||
if isNamedEvaluation(tx.EmitContext(), expression) {
|
||||
expression = transformNamedEvaluation(tx.EmitContext(), expression /*ignoreEmptyStringLiteral*/, false, "default")
|
||||
}
|
||||
}
|
||||
|
||||
return tx.Factory().NewExpressionStatement(expression)
|
||||
}
|
||||
|
||||
func (tx *usingDeclarationTransformer) hoistVariableStatement(node *ast.VariableStatement) *ast.Statement {
|
||||
// NOTE: `node` has already been visited
|
||||
var expressions []*ast.Expression
|
||||
isExported := ast.HasSyntacticModifier(node.AsNode(), ast.ModifierFlagsExport)
|
||||
for _, variable := range node.DeclarationList.AsVariableDeclarationList().Declarations.Nodes {
|
||||
tx.hoistBindingElement(variable, isExported, variable)
|
||||
if variable.Initializer() != nil {
|
||||
expressions = append(expressions, tx.hoistInitializedVariable(variable.AsVariableDeclaration()))
|
||||
}
|
||||
}
|
||||
if len(expressions) > 0 {
|
||||
statement := tx.Factory().NewExpressionStatement(tx.Factory().InlineExpressions(expressions))
|
||||
tx.EmitContext().SetOriginal(statement, node.AsNode())
|
||||
tx.EmitContext().SetCommentRange(statement, node.Loc)
|
||||
tx.EmitContext().SetSourceMapRange(statement, node.Loc)
|
||||
return statement
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tx *usingDeclarationTransformer) hoistInitializedVariable(node *ast.VariableDeclaration) *ast.Expression {
|
||||
// NOTE: `node` has already been visited
|
||||
if node.Initializer == nil {
|
||||
panic("Expected initializer")
|
||||
}
|
||||
var target *ast.Expression
|
||||
if ast.IsIdentifier(node.Name()) {
|
||||
target = node.Name().Clone(tx.Factory())
|
||||
tx.EmitContext().SetEmitFlags(target, tx.EmitContext().EmitFlags(target) & ^(printer.EFLocalName|printer.EFExportName|printer.EFInternalName))
|
||||
} else {
|
||||
target = transformers.ConvertBindingPatternToAssignmentPattern(tx.EmitContext(), node.Name().AsBindingPattern())
|
||||
}
|
||||
|
||||
assignment := tx.Factory().NewAssignmentExpression(target, node.Initializer)
|
||||
tx.EmitContext().SetOriginal(assignment, node.AsNode())
|
||||
tx.EmitContext().SetCommentRange(assignment, node.Loc)
|
||||
tx.EmitContext().SetSourceMapRange(assignment, node.Loc)
|
||||
return assignment
|
||||
}
|
||||
|
||||
func (tx *usingDeclarationTransformer) hoistBindingElement(node *ast.Node /*VariableDeclaration|BindingElement*/, isExportedDeclaration bool, original *ast.Node) {
|
||||
// NOTE: `node` has already been visited
|
||||
if ast.IsBindingPattern(node.Name()) {
|
||||
for _, element := range node.Name().AsBindingPattern().Elements.Nodes {
|
||||
if element.Name() != nil {
|
||||
tx.hoistBindingElement(element, isExportedDeclaration, original)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tx.hoistBindingIdentifier(node.Name(), isExportedDeclaration, nil /*exportAlias*/, original)
|
||||
}
|
||||
}
|
||||
|
||||
func (tx *usingDeclarationTransformer) hoistBindingIdentifier(node *ast.IdentifierNode, isExport bool, exportAlias *ast.IdentifierNode, original *ast.Node) {
|
||||
// NOTE: `node` has already been visited
|
||||
name := node
|
||||
if !transformers.IsGeneratedIdentifier(tx.EmitContext(), node) {
|
||||
name = name.Clone(tx.Factory())
|
||||
}
|
||||
if isExport {
|
||||
if exportAlias == nil && !transformers.IsLocalName(tx.EmitContext(), name) {
|
||||
varDecl := tx.Factory().NewVariableDeclaration(name, nil /*exclamationToken*/, nil /*type*/, nil /*initializer*/)
|
||||
if original != nil {
|
||||
tx.EmitContext().SetOriginal(varDecl, original)
|
||||
}
|
||||
tx.exportVars = append(tx.exportVars, varDecl)
|
||||
return
|
||||
}
|
||||
|
||||
var localName *ast.ModuleExportName
|
||||
var exportName *ast.ModuleExportName
|
||||
if exportAlias != nil {
|
||||
localName = name
|
||||
exportName = exportAlias
|
||||
} else {
|
||||
exportName = name
|
||||
}
|
||||
specifier := tx.Factory().NewExportSpecifier( /*isTypeOnly*/ false, localName, exportName)
|
||||
if original != nil {
|
||||
tx.EmitContext().SetOriginal(specifier, original)
|
||||
}
|
||||
if tx.exportBindings == nil {
|
||||
tx.exportBindings = make(map[string]*ast.ExportSpecifierNode)
|
||||
}
|
||||
tx.exportBindings[name.Text()] = specifier
|
||||
}
|
||||
tx.EmitContext().AddVariableDeclaration(name)
|
||||
}
|
||||
|
||||
func (tx *usingDeclarationTransformer) createEnvBinding() *ast.IdentifierNode {
|
||||
return tx.Factory().NewUniqueName("env")
|
||||
}
|
||||
|
||||
func (tx *usingDeclarationTransformer) createDownlevelUsingStatements(bodyStatements []*ast.Node, envBinding *ast.IdentifierNode, async bool) []*ast.Statement {
|
||||
statements := make([]*ast.Statement, 0, 2)
|
||||
|
||||
// produces:
|
||||
//
|
||||
// const env_1 = { stack: [], error: void 0, hasError: false };
|
||||
//
|
||||
envObject := tx.Factory().NewObjectLiteralExpression(tx.Factory().NewNodeList([]*ast.Expression{
|
||||
tx.Factory().NewPropertyAssignment(nil /*modifiers*/, tx.Factory().NewIdentifier("stack"), nil /*postfixToken*/, nil /*typeNode*/, tx.Factory().NewArrayLiteralExpression(nil, false /*multiLine*/)),
|
||||
tx.Factory().NewPropertyAssignment(nil /*modifiers*/, tx.Factory().NewIdentifier("error"), nil /*postfixToken*/, nil /*typeNode*/, tx.Factory().NewVoidZeroExpression()),
|
||||
tx.Factory().NewPropertyAssignment(nil /*modifiers*/, tx.Factory().NewIdentifier("hasError"), nil /*postfixToken*/, nil /*typeNode*/, tx.Factory().NewFalseExpression()),
|
||||
}), false /*multiLine*/)
|
||||
envVar := tx.Factory().NewVariableDeclaration(envBinding, nil /*exclamationToken*/, nil /*typeNode*/, envObject)
|
||||
envVarList := tx.Factory().NewVariableDeclarationList(ast.NodeFlagsConst, tx.Factory().NewNodeList([]*ast.VariableDeclarationNode{envVar}))
|
||||
envVarStatement := tx.Factory().NewVariableStatement(nil /*modifiers*/, envVarList)
|
||||
statements = append(statements, envVarStatement)
|
||||
|
||||
// when `async` is `false`, produces:
|
||||
//
|
||||
// try {
|
||||
// <bodyStatements>
|
||||
// }
|
||||
// catch (e_1) {
|
||||
// env_1.error = e_1;
|
||||
// env_1.hasError = true;
|
||||
// }
|
||||
// finally {
|
||||
// __disposeResources(env_1);
|
||||
// }
|
||||
|
||||
// when `async` is `true`, produces:
|
||||
//
|
||||
// try {
|
||||
// <bodyStatements>
|
||||
// }
|
||||
// catch (e_1) {
|
||||
// env_1.error = e_1;
|
||||
// env_1.hasError = true;
|
||||
// }
|
||||
// finally {
|
||||
// const result_1 = __disposeResources(env_1);
|
||||
// if (result_1) {
|
||||
// await result_1;
|
||||
// }
|
||||
// }
|
||||
|
||||
// Unfortunately, it is necessary to use two properties to indicate an error because `throw undefined` is legal
|
||||
// JavaScript.
|
||||
tryBlock := tx.Factory().NewBlock(tx.Factory().NewNodeList(bodyStatements), true /*multiLine*/)
|
||||
bodyCatchBinding := tx.Factory().NewUniqueName("e")
|
||||
catchClause := tx.Factory().NewCatchClause(
|
||||
tx.Factory().NewVariableDeclaration(
|
||||
bodyCatchBinding,
|
||||
nil, /*exclamationToken*/
|
||||
nil, /*type*/
|
||||
nil, /*initializer*/
|
||||
),
|
||||
tx.Factory().NewBlock(tx.Factory().NewNodeList([]*ast.Statement{
|
||||
tx.Factory().NewExpressionStatement(
|
||||
tx.Factory().NewAssignmentExpression(
|
||||
tx.Factory().NewPropertyAccessExpression(envBinding, nil, tx.Factory().NewIdentifier("error"), ast.NodeFlagsNone),
|
||||
bodyCatchBinding,
|
||||
),
|
||||
),
|
||||
tx.Factory().NewExpressionStatement(
|
||||
tx.Factory().NewAssignmentExpression(
|
||||
tx.Factory().NewPropertyAccessExpression(envBinding, nil, tx.Factory().NewIdentifier("hasError"), ast.NodeFlagsNone),
|
||||
tx.Factory().NewTrueExpression(),
|
||||
),
|
||||
),
|
||||
}), true /*multiLine*/),
|
||||
)
|
||||
|
||||
var finallyBlock *ast.BlockNode
|
||||
if async {
|
||||
result := tx.Factory().NewUniqueName("result")
|
||||
finallyBlock = tx.Factory().NewBlock(tx.Factory().NewNodeList([]*ast.Statement{
|
||||
tx.Factory().NewVariableStatement(
|
||||
nil, /*modifiers*/
|
||||
tx.Factory().NewVariableDeclarationList(ast.NodeFlagsConst, tx.Factory().NewNodeList([]*ast.VariableDeclarationNode{
|
||||
tx.Factory().NewVariableDeclaration(
|
||||
result,
|
||||
nil, /*exclamationToken*/
|
||||
nil, /*type*/
|
||||
tx.Factory().NewDisposeResourcesHelper(envBinding),
|
||||
),
|
||||
})),
|
||||
),
|
||||
tx.Factory().NewIfStatement(result, tx.Factory().NewExpressionStatement(tx.Factory().NewAwaitExpression(result)), nil /*elseStatement*/),
|
||||
}), true /*multiLine*/)
|
||||
} else {
|
||||
finallyBlock = tx.Factory().NewBlock(tx.Factory().NewNodeList([]*ast.Statement{
|
||||
tx.Factory().NewExpressionStatement(
|
||||
tx.Factory().NewDisposeResourcesHelper(envBinding),
|
||||
),
|
||||
}), true /*multiLine*/)
|
||||
}
|
||||
|
||||
tryStatement := tx.Factory().NewTryStatement(tryBlock, catchClause, finallyBlock)
|
||||
statements = append(statements, tryStatement)
|
||||
return statements
|
||||
}
|
||||
|
||||
func isUsingVariableDeclarationList(node *ast.ForInitializer) bool {
|
||||
return ast.IsVariableDeclarationList(node) && getUsingKindOfVariableDeclarationList(node.AsVariableDeclarationList()) != usingKindNone
|
||||
}
|
||||
|
||||
func getUsingKindOfVariableDeclarationList(node *ast.VariableDeclarationList) usingKind {
|
||||
switch node.Flags & ast.NodeFlagsBlockScoped {
|
||||
case ast.NodeFlagsAwaitUsing:
|
||||
return usingKindAsync
|
||||
case ast.NodeFlagsUsing:
|
||||
return usingKindSync
|
||||
default:
|
||||
return usingKindNone
|
||||
}
|
||||
}
|
||||
|
||||
func getUsingKindOfVariableStatement(node *ast.VariableStatement) usingKind {
|
||||
return getUsingKindOfVariableDeclarationList(node.DeclarationList.AsVariableDeclarationList())
|
||||
}
|
||||
|
||||
func getUsingKind(statement *ast.Node) usingKind {
|
||||
if ast.IsVariableStatement(statement) {
|
||||
return getUsingKindOfVariableStatement(statement.AsVariableStatement())
|
||||
}
|
||||
return usingKindNone
|
||||
}
|
||||
|
||||
func getUsingKindOfStatements(statements []*ast.Node) usingKind {
|
||||
result := usingKindNone
|
||||
for _, statement := range statements {
|
||||
usingKind := getUsingKind(statement)
|
||||
if usingKind == usingKindAsync {
|
||||
return usingKindAsync
|
||||
}
|
||||
if usingKind > result {
|
||||
result = usingKind
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func getUsingKindOfCaseOrDefaultClauses(clauses []*ast.CaseOrDefaultClauseNode) usingKind {
|
||||
result := usingKindNone
|
||||
for _, clause := range clauses {
|
||||
usingKind := getUsingKindOfStatements(clause.AsCaseOrDefaultClause().Statements.Nodes)
|
||||
if usingKind == usingKindAsync {
|
||||
return usingKindAsync
|
||||
}
|
||||
if usingKind > result {
|
||||
result = usingKind
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
@ -1,49 +0,0 @@
|
||||
package estransforms
|
||||
|
||||
import (
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers"
|
||||
)
|
||||
|
||||
func convertClassDeclarationToClassExpression(emitContext *printer.EmitContext, node *ast.ClassDeclaration) *ast.Expression {
|
||||
updated := emitContext.Factory.NewClassExpression(
|
||||
transformers.ExtractModifiers(emitContext, node.Modifiers(), ^ast.ModifierFlagsExportDefault),
|
||||
node.Name(),
|
||||
node.TypeParameters,
|
||||
node.HeritageClauses,
|
||||
node.Members,
|
||||
)
|
||||
emitContext.SetOriginal(updated, node.AsNode())
|
||||
updated.Loc = node.Loc
|
||||
return updated
|
||||
}
|
||||
|
||||
func createNotNullCondition(emitContext *printer.EmitContext, left *ast.Node, right *ast.Node, invert bool) *ast.Node {
|
||||
token := ast.KindExclamationEqualsEqualsToken
|
||||
op := ast.KindAmpersandAmpersandToken
|
||||
if invert {
|
||||
token = ast.KindEqualsEqualsEqualsToken
|
||||
op = ast.KindBarBarToken
|
||||
}
|
||||
|
||||
return emitContext.Factory.NewBinaryExpression(
|
||||
nil,
|
||||
emitContext.Factory.NewBinaryExpression(
|
||||
nil,
|
||||
left,
|
||||
nil,
|
||||
emitContext.Factory.NewToken(token),
|
||||
emitContext.Factory.NewKeywordExpression(ast.KindNullKeyword),
|
||||
),
|
||||
nil,
|
||||
emitContext.Factory.NewToken(op),
|
||||
emitContext.Factory.NewBinaryExpression(
|
||||
nil,
|
||||
right,
|
||||
nil,
|
||||
emitContext.Factory.NewToken(token),
|
||||
emitContext.Factory.NewVoidZeroExpression(),
|
||||
),
|
||||
)
|
||||
}
|
||||
@ -1,88 +0,0 @@
|
||||
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, "*/", "*_/")
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,20 +0,0 @@
|
||||
package jsxtransforms
|
||||
|
||||
import "efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
|
||||
func createExpressionFromEntityName(factory ast.NodeFactoryCoercible, node *ast.Node) *ast.Expression {
|
||||
if ast.IsQualifiedName(node) {
|
||||
left := createExpressionFromEntityName(factory, node.AsQualifiedName().Left)
|
||||
// TODO(rbuckton): Does this need to be parented?
|
||||
right := node.AsQualifiedName().Right.Clone(factory.AsNodeFactory())
|
||||
right.Loc = node.AsQualifiedName().Right.Loc
|
||||
right.Parent = node.AsQualifiedName().Right.Parent
|
||||
return factory.AsNodeFactory().NewPropertyAccessExpression(left, nil, right, ast.NodeFlagsNone)
|
||||
} else {
|
||||
// TODO(rbuckton): Does this need to be parented?
|
||||
res := node.Clone(factory.AsNodeFactory())
|
||||
res.Loc = node.Loc
|
||||
res.Parent = node.Parent
|
||||
return res
|
||||
}
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
package transformers
|
||||
|
||||
import (
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
|
||||
)
|
||||
|
||||
type modifierVisitor struct {
|
||||
Transformer
|
||||
AllowedModifiers ast.ModifierFlags
|
||||
}
|
||||
|
||||
func (v *modifierVisitor) visit(node *ast.Node) *ast.Node {
|
||||
flags := ast.ModifierToFlag(node.Kind)
|
||||
if flags != ast.ModifierFlagsNone && flags&v.AllowedModifiers == 0 {
|
||||
return nil
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
func ExtractModifiers(emitContext *printer.EmitContext, modifiers *ast.ModifierList, allowed ast.ModifierFlags) *ast.ModifierList {
|
||||
if modifiers == nil {
|
||||
return nil
|
||||
}
|
||||
tx := modifierVisitor{AllowedModifiers: allowed}
|
||||
tx.NewTransformer(tx.visit, emitContext)
|
||||
return tx.visitor.VisitModifiers(modifiers)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,370 +0,0 @@
|
||||
package moduletransforms
|
||||
|
||||
import (
|
||||
"slices"
|
||||
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/binder"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers"
|
||||
)
|
||||
|
||||
type ESModuleTransformer struct {
|
||||
transformers.Transformer
|
||||
compilerOptions *core.CompilerOptions
|
||||
resolver binder.ReferenceResolver
|
||||
getEmitModuleFormatOfFile func(file ast.HasFileName) core.ModuleKind
|
||||
currentSourceFile *ast.SourceFile
|
||||
importRequireStatements *importRequireStatements
|
||||
helperNameSubstitutions map[string]*ast.IdentifierNode
|
||||
}
|
||||
|
||||
type importRequireStatements struct {
|
||||
statements []*ast.Statement
|
||||
requireHelperName *ast.IdentifierNode
|
||||
}
|
||||
|
||||
func NewESModuleTransformer(opts *transformers.TransformOptions) *transformers.Transformer {
|
||||
compilerOptions := opts.CompilerOptions
|
||||
resolver := opts.Resolver
|
||||
if resolver == nil {
|
||||
resolver = binder.NewReferenceResolver(compilerOptions, binder.ReferenceResolverHooks{})
|
||||
}
|
||||
tx := &ESModuleTransformer{compilerOptions: compilerOptions, resolver: resolver, getEmitModuleFormatOfFile: opts.GetEmitModuleFormatOfFile}
|
||||
return tx.NewTransformer(tx.visit, opts.Context)
|
||||
}
|
||||
|
||||
// Visits source elements that are not top-level or top-level nested statements.
|
||||
func (tx *ESModuleTransformer) visit(node *ast.Node) *ast.Node {
|
||||
switch node.Kind {
|
||||
case ast.KindSourceFile:
|
||||
node = tx.visitSourceFile(node.AsSourceFile())
|
||||
case ast.KindImportDeclaration:
|
||||
node = tx.visitImportDeclaration(node.AsImportDeclaration())
|
||||
case ast.KindImportEqualsDeclaration:
|
||||
node = tx.visitImportEqualsDeclaration(node.AsImportEqualsDeclaration())
|
||||
case ast.KindExportAssignment:
|
||||
node = tx.visitExportAssignment(node.AsExportAssignment())
|
||||
case ast.KindExportDeclaration:
|
||||
node = tx.visitExportDeclaration(node.AsExportDeclaration())
|
||||
case ast.KindCallExpression:
|
||||
node = tx.visitCallExpression(node.AsCallExpression())
|
||||
default:
|
||||
node = tx.Visitor().VisitEachChild(node)
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
func (tx *ESModuleTransformer) visitSourceFile(node *ast.SourceFile) *ast.Node {
|
||||
if node.IsDeclarationFile ||
|
||||
!(ast.IsExternalModule(node) || tx.compilerOptions.GetIsolatedModules()) {
|
||||
return node.AsNode()
|
||||
}
|
||||
|
||||
tx.currentSourceFile = node
|
||||
tx.importRequireStatements = nil
|
||||
|
||||
result := tx.Visitor().VisitEachChild(node.AsNode()).AsSourceFile()
|
||||
tx.EmitContext().AddEmitHelper(result.AsNode(), tx.EmitContext().ReadEmitHelpers()...)
|
||||
|
||||
externalHelpersImportDeclaration := createExternalHelpersImportDeclarationIfNeeded(tx.EmitContext(), result, tx.compilerOptions, tx.getEmitModuleFormatOfFile(node), false /*hasExportStarsToExportValues*/, false /*hasImportStar*/, false /*hasImportDefault*/)
|
||||
if externalHelpersImportDeclaration != nil || tx.importRequireStatements != nil {
|
||||
prologue, rest := tx.Factory().SplitStandardPrologue(result.Statements.Nodes)
|
||||
statements := slices.Clone(prologue)
|
||||
if externalHelpersImportDeclaration != nil {
|
||||
statements = append(statements, externalHelpersImportDeclaration)
|
||||
}
|
||||
if tx.importRequireStatements != nil {
|
||||
statements = append(statements, tx.importRequireStatements.statements...)
|
||||
}
|
||||
statements = append(statements, rest...)
|
||||
statementList := tx.Factory().NewNodeList(statements)
|
||||
statementList.Loc = result.Statements.Loc
|
||||
result = tx.Factory().UpdateSourceFile(result, statementList, node.EndOfFileToken).AsSourceFile()
|
||||
}
|
||||
|
||||
if ast.IsExternalModule(result) &&
|
||||
tx.compilerOptions.GetEmitModuleKind() != core.ModuleKindPreserve &&
|
||||
!core.Some(result.Statements.Nodes, ast.IsExternalModuleIndicator) {
|
||||
statements := slices.Clone(result.Statements.Nodes)
|
||||
statements = append(statements, createEmptyImports(tx.Factory()))
|
||||
statementList := tx.Factory().NewNodeList(statements)
|
||||
statementList.Loc = result.Statements.Loc
|
||||
result = tx.Factory().UpdateSourceFile(result, statementList, node.EndOfFileToken).AsSourceFile()
|
||||
}
|
||||
|
||||
tx.importRequireStatements = nil
|
||||
tx.currentSourceFile = nil
|
||||
return result.AsNode()
|
||||
}
|
||||
|
||||
func (tx *ESModuleTransformer) visitImportDeclaration(node *ast.ImportDeclaration) *ast.Node {
|
||||
if !tx.compilerOptions.RewriteRelativeImportExtensions.IsTrue() {
|
||||
return node.AsNode()
|
||||
}
|
||||
updatedModuleSpecifier := rewriteModuleSpecifier(tx.EmitContext(), node.ModuleSpecifier, tx.compilerOptions)
|
||||
return tx.Factory().UpdateImportDeclaration(
|
||||
node,
|
||||
nil, /*modifiers*/
|
||||
tx.Visitor().VisitNode(node.ImportClause),
|
||||
updatedModuleSpecifier,
|
||||
tx.Visitor().VisitNode(node.Attributes),
|
||||
)
|
||||
}
|
||||
|
||||
func (tx *ESModuleTransformer) visitImportEqualsDeclaration(node *ast.ImportEqualsDeclaration) *ast.Node {
|
||||
// Though an error in es2020 modules, in node-flavor es2020 modules, we can helpfully transform this to a synthetic `require` call
|
||||
// To give easy access to a synchronous `require` in node-flavor esm. We do the transform even in scenarios where we error, but `import.meta.url`
|
||||
// is available, just because the output is reasonable for a node-like runtime.
|
||||
if tx.compilerOptions.GetEmitModuleKind() < core.ModuleKindNode16 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !ast.IsExternalModuleImportEqualsDeclaration(node.AsNode()) {
|
||||
panic("import= for internal module references should be handled in an earlier transformer.")
|
||||
}
|
||||
|
||||
varStatement := tx.Factory().NewVariableStatement(
|
||||
nil, /*modifiers*/
|
||||
tx.Factory().NewVariableDeclarationList(
|
||||
ast.NodeFlagsConst,
|
||||
tx.Factory().NewNodeList([]*ast.Node{
|
||||
tx.Factory().NewVariableDeclaration(
|
||||
node.Name().Clone(tx.Factory()),
|
||||
nil, /*exclamationToken*/
|
||||
nil, /*type*/
|
||||
tx.createRequireCall(node.AsNode()),
|
||||
),
|
||||
}),
|
||||
),
|
||||
)
|
||||
tx.EmitContext().SetOriginal(varStatement, node.AsNode())
|
||||
tx.EmitContext().AssignCommentAndSourceMapRanges(varStatement, node.AsNode())
|
||||
|
||||
var statements []*ast.Statement
|
||||
statements = append(statements, varStatement)
|
||||
statements = tx.appendExportsOfImportEqualsDeclaration(statements, node)
|
||||
return transformers.SingleOrMany(statements, tx.Factory())
|
||||
}
|
||||
|
||||
func (tx *ESModuleTransformer) appendExportsOfImportEqualsDeclaration(statements []*ast.Statement, node *ast.ImportEqualsDeclaration) []*ast.Statement {
|
||||
if ast.HasSyntacticModifier(node.AsNode(), ast.ModifierFlagsExport) {
|
||||
statements = append(statements, tx.Factory().NewExportDeclaration(
|
||||
nil, /*modifiers*/
|
||||
false, /*isTypeOnly*/
|
||||
tx.Factory().NewNamedExports(
|
||||
tx.Factory().NewNodeList([]*ast.Node{
|
||||
tx.Factory().NewExportSpecifier(
|
||||
false, /*isTypeOnly*/
|
||||
nil, /*propertyName*/
|
||||
node.Name().Clone(tx.Factory()),
|
||||
),
|
||||
}),
|
||||
),
|
||||
nil, /*moduleSpecifier*/
|
||||
nil, /*attributes*/
|
||||
))
|
||||
}
|
||||
return statements
|
||||
}
|
||||
|
||||
func (tx *ESModuleTransformer) visitExportAssignment(node *ast.ExportAssignment) *ast.Node {
|
||||
if !node.IsExportEquals {
|
||||
return tx.Visitor().VisitEachChild(node.AsNode())
|
||||
}
|
||||
if tx.compilerOptions.GetEmitModuleKind() != core.ModuleKindPreserve {
|
||||
// Elide `export=` as it is not legal with --module ES6
|
||||
return nil
|
||||
}
|
||||
statement := tx.Factory().NewExpressionStatement(
|
||||
tx.Factory().NewAssignmentExpression(
|
||||
tx.Factory().NewPropertyAccessExpression(
|
||||
tx.Factory().NewIdentifier("module"),
|
||||
nil, /*questionDotToken*/
|
||||
tx.Factory().NewIdentifier("exports"),
|
||||
ast.NodeFlagsNone,
|
||||
),
|
||||
tx.Visitor().VisitNode(node.Expression),
|
||||
),
|
||||
)
|
||||
tx.EmitContext().SetOriginal(statement, node.AsNode())
|
||||
return statement
|
||||
}
|
||||
|
||||
func (tx *ESModuleTransformer) visitExportDeclaration(node *ast.ExportDeclaration) *ast.Node {
|
||||
if node.ModuleSpecifier == nil {
|
||||
return node.AsNode()
|
||||
}
|
||||
|
||||
updatedModuleSpecifier := rewriteModuleSpecifier(tx.EmitContext(), node.ModuleSpecifier, tx.compilerOptions)
|
||||
if tx.compilerOptions.Module > core.ModuleKindES2015 || node.ExportClause == nil || !ast.IsNamespaceExport(node.ExportClause) {
|
||||
// Either ill-formed or don't need to be transformed.
|
||||
return tx.Factory().UpdateExportDeclaration(
|
||||
node,
|
||||
nil, /*modifiers*/
|
||||
false, /*isTypeOnly*/
|
||||
node.ExportClause,
|
||||
updatedModuleSpecifier,
|
||||
tx.Visitor().VisitNode(node.Attributes),
|
||||
)
|
||||
}
|
||||
|
||||
oldIdentifier := node.ExportClause.Name()
|
||||
synthName := tx.Factory().NewGeneratedNameForNode(oldIdentifier)
|
||||
importDecl := tx.Factory().NewImportDeclaration(
|
||||
nil, /*modifiers*/
|
||||
tx.Factory().NewImportClause(
|
||||
ast.KindUnknown, /*phaseModifier*/
|
||||
nil, /*name*/
|
||||
tx.Factory().NewNamespaceImport(synthName),
|
||||
),
|
||||
updatedModuleSpecifier,
|
||||
tx.Visitor().VisitNode(node.Attributes),
|
||||
)
|
||||
tx.EmitContext().SetOriginal(importDecl, node.ExportClause)
|
||||
|
||||
var exportDecl *ast.Node
|
||||
if ast.IsExportNamespaceAsDefaultDeclaration(node.AsNode()) {
|
||||
exportDecl = tx.Factory().NewExportAssignment(nil /*modifiers*/, false /*isExportEquals*/, nil /*typeNode*/, synthName)
|
||||
} else {
|
||||
exportDecl = tx.Factory().NewExportDeclaration(
|
||||
nil, /*modifiers*/
|
||||
false, /*isTypeOnly*/
|
||||
tx.Factory().NewNamedExports(
|
||||
tx.Factory().NewNodeList([]*ast.Node{
|
||||
tx.Factory().NewExportSpecifier(false /*isTypeOnly*/, synthName, oldIdentifier),
|
||||
}),
|
||||
),
|
||||
nil, /*moduleSpecifier*/
|
||||
nil, /*attributes*/
|
||||
)
|
||||
}
|
||||
tx.EmitContext().SetOriginal(exportDecl, node.AsNode())
|
||||
return transformers.SingleOrMany([]*ast.Statement{importDecl, exportDecl}, tx.Factory())
|
||||
}
|
||||
|
||||
func (tx *ESModuleTransformer) visitCallExpression(node *ast.CallExpression) *ast.Node {
|
||||
if tx.compilerOptions.RewriteRelativeImportExtensions.IsTrue() {
|
||||
if ast.IsImportCall(node.AsNode()) && len(node.Arguments.Nodes) > 0 ||
|
||||
ast.IsInJSFile(node.AsNode()) && ast.IsRequireCall(node.AsNode(), false /*requireStringLiteralLikeArgument*/) {
|
||||
return tx.visitImportOrRequireCall(node)
|
||||
}
|
||||
}
|
||||
return tx.Visitor().VisitEachChild(node.AsNode())
|
||||
}
|
||||
|
||||
func (tx *ESModuleTransformer) visitImportOrRequireCall(node *ast.CallExpression) *ast.Node {
|
||||
if len(node.Arguments.Nodes) == 0 {
|
||||
return tx.Visitor().VisitEachChild(node.AsNode())
|
||||
}
|
||||
|
||||
expression := tx.Visitor().VisitNode(node.Expression)
|
||||
|
||||
var argument *ast.Expression
|
||||
if ast.IsStringLiteralLike(node.Arguments.Nodes[0]) {
|
||||
argument = rewriteModuleSpecifier(tx.EmitContext(), node.Arguments.Nodes[0], tx.compilerOptions)
|
||||
} else {
|
||||
argument = tx.Factory().NewRewriteRelativeImportExtensionsHelper(node.Arguments.Nodes[0], tx.compilerOptions.Jsx == core.JsxEmitPreserve)
|
||||
}
|
||||
|
||||
var arguments []*ast.Expression
|
||||
arguments = append(arguments, argument)
|
||||
|
||||
rest := core.FirstResult(tx.Visitor().VisitSlice(node.Arguments.Nodes[1:]))
|
||||
arguments = append(arguments, rest...)
|
||||
|
||||
argumentList := tx.Factory().NewNodeList(arguments)
|
||||
argumentList.Loc = node.Arguments.Loc
|
||||
return tx.Factory().UpdateCallExpression(
|
||||
node,
|
||||
expression,
|
||||
node.QuestionDotToken,
|
||||
nil, /*typeArguments*/
|
||||
argumentList,
|
||||
)
|
||||
}
|
||||
|
||||
func (tx *ESModuleTransformer) createRequireCall(node *ast.Node /*ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration*/) *ast.Expression {
|
||||
moduleName := getExternalModuleNameLiteral(tx.Factory(), node, tx.currentSourceFile, nil /*host*/, nil /*emitResolver*/, tx.compilerOptions)
|
||||
|
||||
var args []*ast.Expression
|
||||
if moduleName != nil {
|
||||
args = append(args, rewriteModuleSpecifier(tx.EmitContext(), moduleName, tx.compilerOptions))
|
||||
}
|
||||
|
||||
if tx.compilerOptions.GetEmitModuleKind() == core.ModuleKindPreserve {
|
||||
return tx.Factory().NewCallExpression(
|
||||
tx.Factory().NewIdentifier("require"),
|
||||
nil, /*questionDotToken*/
|
||||
nil, /*typeArguments*/
|
||||
tx.Factory().NewNodeList(args),
|
||||
ast.NodeFlagsNone,
|
||||
)
|
||||
}
|
||||
|
||||
if tx.importRequireStatements == nil {
|
||||
createRequireName := tx.Factory().NewUniqueNameEx("_createRequire", printer.AutoGenerateOptions{Flags: printer.GeneratedIdentifierFlagsOptimistic | printer.GeneratedIdentifierFlagsFileLevel})
|
||||
importStatement := tx.Factory().NewImportDeclaration(
|
||||
nil, /*modifiers*/
|
||||
tx.Factory().NewImportClause(
|
||||
ast.KindUnknown, /*phaseModifier*/
|
||||
nil, /*name*/
|
||||
tx.Factory().NewNamedImports(
|
||||
tx.Factory().NewNodeList([]*ast.Node{
|
||||
tx.Factory().NewImportSpecifier(
|
||||
false, /*isTypeOnly*/
|
||||
tx.Factory().NewIdentifier("createRequire"),
|
||||
createRequireName,
|
||||
),
|
||||
}),
|
||||
),
|
||||
),
|
||||
tx.Factory().NewStringLiteral("module"),
|
||||
nil, /*attributes*/
|
||||
)
|
||||
tx.EmitContext().AddEmitFlags(importStatement, printer.EFCustomPrologue)
|
||||
|
||||
requireHelperName := tx.Factory().NewUniqueNameEx("__require", printer.AutoGenerateOptions{Flags: printer.GeneratedIdentifierFlagsOptimistic | printer.GeneratedIdentifierFlagsFileLevel})
|
||||
requireStatement := tx.Factory().NewVariableStatement(
|
||||
nil, /*modifiers*/
|
||||
tx.Factory().NewVariableDeclarationList(
|
||||
ast.NodeFlagsConst,
|
||||
tx.Factory().NewNodeList([]*ast.Node{
|
||||
tx.Factory().NewVariableDeclaration(
|
||||
requireHelperName,
|
||||
nil, /*exclamationToken*/
|
||||
nil, /*type*/
|
||||
tx.Factory().NewCallExpression(
|
||||
createRequireName.Clone(tx.Factory()),
|
||||
nil, /*questionDotToken*/
|
||||
nil, /*typeArguments*/
|
||||
tx.Factory().NewNodeList([]*ast.Expression{
|
||||
tx.Factory().NewPropertyAccessExpression(
|
||||
tx.Factory().NewMetaProperty(ast.KindImportKeyword, tx.Factory().NewIdentifier("meta")),
|
||||
nil, /*questionDotToken*/
|
||||
tx.Factory().NewIdentifier("url"),
|
||||
ast.NodeFlagsNone,
|
||||
),
|
||||
}),
|
||||
ast.NodeFlagsNone,
|
||||
),
|
||||
),
|
||||
}),
|
||||
),
|
||||
)
|
||||
tx.EmitContext().AddEmitFlags(requireStatement, printer.EFCustomPrologue)
|
||||
tx.importRequireStatements = &importRequireStatements{
|
||||
statements: []*ast.Statement{importStatement, requireStatement},
|
||||
requireHelperName: requireHelperName,
|
||||
}
|
||||
}
|
||||
|
||||
return tx.Factory().NewCallExpression(
|
||||
tx.importRequireStatements.requireHelperName.Clone(tx.Factory()),
|
||||
nil, /*questionDotToken*/
|
||||
nil, /*typeArguments*/
|
||||
tx.Factory().NewNodeList(args),
|
||||
ast.NodeFlagsNone,
|
||||
)
|
||||
}
|
||||
@ -1,249 +0,0 @@
|
||||
package moduletransforms_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/binder"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/testutil/emittestutil"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/testutil/parsetestutil"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers/moduletransforms"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers/tstransforms"
|
||||
)
|
||||
|
||||
func TestESModuleTransformer(t *testing.T) {
|
||||
t.Parallel()
|
||||
data := []struct {
|
||||
title string
|
||||
input string
|
||||
output string
|
||||
other string
|
||||
jsx bool
|
||||
options *core.CompilerOptions
|
||||
}{
|
||||
// ImportDeclaration
|
||||
{
|
||||
title: "ImportDeclaration#1",
|
||||
input: `import "other"`,
|
||||
output: `import "other";`,
|
||||
},
|
||||
{
|
||||
title: "ImportDeclaration#2",
|
||||
input: `import "./other.ts"`,
|
||||
output: `import "./other.js";`,
|
||||
options: &core.CompilerOptions{RewriteRelativeImportExtensions: core.TSTrue},
|
||||
},
|
||||
{
|
||||
title: "ImportDeclaration#3",
|
||||
input: `import "./other.tsx"`,
|
||||
output: `import "./other.js";`,
|
||||
options: &core.CompilerOptions{RewriteRelativeImportExtensions: core.TSTrue},
|
||||
},
|
||||
{
|
||||
title: "ImportDeclaration#4",
|
||||
input: `import "./other.tsx"`,
|
||||
output: `import "./other.jsx";`,
|
||||
options: &core.CompilerOptions{RewriteRelativeImportExtensions: core.TSTrue, Jsx: core.JsxEmitPreserve},
|
||||
},
|
||||
|
||||
// ImportEqualsDeclaration
|
||||
{
|
||||
title: "ImportEqualsDeclaration#1",
|
||||
input: `import x = require("other")`,
|
||||
output: `export {};`,
|
||||
},
|
||||
{
|
||||
title: "ImportEqualsDeclaration#2",
|
||||
input: `import x = require("other")`,
|
||||
output: `import { createRequire as _createRequire } from "module";
|
||||
const __require = _createRequire(import.meta.url);
|
||||
const x = __require("other");`,
|
||||
options: &core.CompilerOptions{Module: core.ModuleKindNode16},
|
||||
},
|
||||
{
|
||||
title: "ImportEqualsDeclaration#3",
|
||||
input: `import x = require("./other.ts")`,
|
||||
output: `import { createRequire as _createRequire } from "module";
|
||||
const __require = _createRequire(import.meta.url);
|
||||
const x = __require("./other.js");`,
|
||||
options: &core.CompilerOptions{Module: core.ModuleKindNode16, RewriteRelativeImportExtensions: core.TSTrue},
|
||||
},
|
||||
{
|
||||
title: "ImportEqualsDeclaration#4",
|
||||
input: `import x = require("./other.tsx")`,
|
||||
output: `import { createRequire as _createRequire } from "module";
|
||||
const __require = _createRequire(import.meta.url);
|
||||
const x = __require("./other.js");`,
|
||||
options: &core.CompilerOptions{Module: core.ModuleKindNode16, RewriteRelativeImportExtensions: core.TSTrue},
|
||||
},
|
||||
{
|
||||
title: "ImportEqualsDeclaration#5",
|
||||
input: `import x = require("./other.tsx")`,
|
||||
output: `import { createRequire as _createRequire } from "module";
|
||||
const __require = _createRequire(import.meta.url);
|
||||
const x = __require("./other.jsx");`,
|
||||
options: &core.CompilerOptions{Module: core.ModuleKindNode16, RewriteRelativeImportExtensions: core.TSTrue, Jsx: core.JsxEmitPreserve},
|
||||
},
|
||||
{
|
||||
title: "ImportEqualsDeclaration#6",
|
||||
input: `export import x = require("other")`,
|
||||
output: `import { createRequire as _createRequire } from "module";
|
||||
const __require = _createRequire(import.meta.url);
|
||||
const x = __require("other");
|
||||
export { x };`,
|
||||
options: &core.CompilerOptions{Module: core.ModuleKindNode16},
|
||||
},
|
||||
|
||||
// ExportAssignment
|
||||
{
|
||||
title: "ExportAssignment#1",
|
||||
input: `export = x`,
|
||||
output: `export {};`,
|
||||
},
|
||||
{
|
||||
title: "ExportAssignment#2",
|
||||
input: `export = x`,
|
||||
output: `module.exports = x;`,
|
||||
options: &core.CompilerOptions{Module: core.ModuleKindPreserve},
|
||||
},
|
||||
|
||||
// ExportDeclaration
|
||||
{
|
||||
title: "ExportDeclaration#1",
|
||||
input: `export * from "other";`,
|
||||
output: `export * from "other";`,
|
||||
},
|
||||
{
|
||||
title: "ExportDeclaration#2",
|
||||
input: `export * from "./other.ts";`,
|
||||
output: `export * from "./other.js";`,
|
||||
options: &core.CompilerOptions{RewriteRelativeImportExtensions: core.TSTrue},
|
||||
},
|
||||
{
|
||||
title: "ExportDeclaration#3",
|
||||
input: `export * as x from "other";`,
|
||||
output: `export * as x from "other";`,
|
||||
options: &core.CompilerOptions{Module: core.ModuleKindESNext},
|
||||
},
|
||||
{
|
||||
title: "ExportDeclaration#4",
|
||||
input: `export { x } from "other";`,
|
||||
output: `export { x } from "other";`,
|
||||
},
|
||||
{
|
||||
title: "ExportDeclaration#5",
|
||||
input: `export * as x from "other";`,
|
||||
output: `import * as x_1 from "other";
|
||||
export { x_1 as x };`,
|
||||
},
|
||||
{
|
||||
title: "ExportDeclaration#6",
|
||||
input: `export * as default from "other";`,
|
||||
output: `import * as default_1 from "other";
|
||||
export default default_1;`,
|
||||
},
|
||||
|
||||
// CallExpression
|
||||
{
|
||||
title: "CallExpression#1",
|
||||
input: `import("other");`,
|
||||
output: `import("other");`,
|
||||
},
|
||||
{
|
||||
title: "CallExpression#2",
|
||||
input: `import(x);`,
|
||||
output: `import(x);`,
|
||||
},
|
||||
{
|
||||
title: "CallExpression#3",
|
||||
input: `export {};
|
||||
import("./other.ts");`,
|
||||
output: `export {};
|
||||
import("./other.js");`,
|
||||
options: &core.CompilerOptions{RewriteRelativeImportExtensions: core.TSTrue},
|
||||
},
|
||||
{
|
||||
title: "CallExpression#4",
|
||||
input: `export {};
|
||||
import(x);`,
|
||||
output: `var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
||||
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
||||
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
||||
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
||||
});
|
||||
}
|
||||
return path;
|
||||
};
|
||||
export {};
|
||||
import(__rewriteRelativeImportExtension(x));`,
|
||||
options: &core.CompilerOptions{RewriteRelativeImportExtensions: core.TSTrue},
|
||||
},
|
||||
{
|
||||
title: "CallExpression#5",
|
||||
input: `export {};
|
||||
import(x);`,
|
||||
output: `var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
||||
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
||||
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
||||
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
||||
});
|
||||
}
|
||||
return path;
|
||||
};
|
||||
export {};
|
||||
import(__rewriteRelativeImportExtension(x, true));`,
|
||||
options: &core.CompilerOptions{RewriteRelativeImportExtensions: core.TSTrue, Jsx: core.JsxEmitPreserve},
|
||||
},
|
||||
{
|
||||
title: "CallExpression#6",
|
||||
input: `export {};
|
||||
import(x);`,
|
||||
output: `import { __rewriteRelativeImportExtension } from "tslib";
|
||||
export {};
|
||||
import(__rewriteRelativeImportExtension(x));`,
|
||||
options: &core.CompilerOptions{Module: core.ModuleKindESNext, RewriteRelativeImportExtensions: core.TSTrue, ImportHelpers: core.TSTrue},
|
||||
},
|
||||
{
|
||||
title: "CallExpression#7",
|
||||
input: `export {};
|
||||
import(x);
|
||||
var __rewriteRelativeImportExtension;`,
|
||||
output: `import { __rewriteRelativeImportExtension as __rewriteRelativeImportExtension_1 } from "tslib";
|
||||
export {};
|
||||
import(__rewriteRelativeImportExtension_1(x));
|
||||
var __rewriteRelativeImportExtension;`,
|
||||
options: &core.CompilerOptions{Module: core.ModuleKindESNext, RewriteRelativeImportExtensions: core.TSTrue, ImportHelpers: core.TSTrue},
|
||||
},
|
||||
}
|
||||
for _, rec := range data {
|
||||
t.Run(rec.title, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
compilerOptions := rec.options
|
||||
if compilerOptions == nil {
|
||||
compilerOptions = &core.CompilerOptions{}
|
||||
}
|
||||
|
||||
file := parsetestutil.ParseTypeScript(rec.input, rec.jsx)
|
||||
parsetestutil.CheckDiagnostics(t, file)
|
||||
binder.BindSourceFile(file)
|
||||
|
||||
var other *ast.SourceFile
|
||||
if len(rec.other) > 0 {
|
||||
other = parsetestutil.ParseTypeScript(rec.other, rec.jsx)
|
||||
parsetestutil.CheckDiagnostics(t, other)
|
||||
binder.BindSourceFile(other)
|
||||
}
|
||||
|
||||
emitContext := printer.NewEmitContext()
|
||||
resolver := binder.NewReferenceResolver(compilerOptions, binder.ReferenceResolverHooks{})
|
||||
opts := transformers.TransformOptions{CompilerOptions: compilerOptions, Context: emitContext, Resolver: resolver, GetEmitModuleFormatOfFile: fakeGetEmitModuleFormatOfFile}
|
||||
file = tstransforms.NewRuntimeSyntaxTransformer(&opts).TransformSourceFile(file)
|
||||
file = moduletransforms.NewESModuleTransformer(&opts).TransformSourceFile(file)
|
||||
emittestutil.CheckEmit(t, emitContext, file, rec.output)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1,390 +0,0 @@
|
||||
package moduletransforms
|
||||
|
||||
import (
|
||||
"slices"
|
||||
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/binder"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/collections"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/stringutil"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers"
|
||||
)
|
||||
|
||||
type externalModuleInfo struct {
|
||||
externalImports []*ast.Declaration // ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration. imports and reexports of other external modules
|
||||
exportSpecifiers collections.MultiMap[string, *ast.ExportSpecifier] // Maps local names to their associated export specifiers (excludes reexports)
|
||||
exportedBindings collections.MultiMap[*ast.Declaration, *ast.ModuleExportName] // Maps local declarations to their associated export aliases
|
||||
exportedNames []*ast.ModuleExportName // all exported names in the module, both local and re-exported, excluding the names of locally exported function declarations
|
||||
exportedFunctions collections.OrderedSet[*ast.FunctionDeclarationNode] // all of the top-level exported function declarations
|
||||
exportEquals *ast.ExportAssignment // an export=/module.exports= declaration if one was present
|
||||
hasExportStarsToExportValues bool // whether this module contains export*
|
||||
}
|
||||
|
||||
type externalModuleInfoCollector struct {
|
||||
sourceFile *ast.SourceFile
|
||||
compilerOptions *core.CompilerOptions
|
||||
emitContext *printer.EmitContext
|
||||
resolver binder.ReferenceResolver
|
||||
uniqueExports collections.Set[string]
|
||||
hasExportDefault bool
|
||||
output *externalModuleInfo
|
||||
}
|
||||
|
||||
func collectExternalModuleInfo(sourceFile *ast.SourceFile, compilerOptions *core.CompilerOptions, emitContext *printer.EmitContext, resolver binder.ReferenceResolver) *externalModuleInfo {
|
||||
c := externalModuleInfoCollector{
|
||||
sourceFile: sourceFile,
|
||||
compilerOptions: compilerOptions,
|
||||
emitContext: emitContext,
|
||||
resolver: resolver,
|
||||
output: &externalModuleInfo{},
|
||||
}
|
||||
return c.collect()
|
||||
}
|
||||
|
||||
func (c *externalModuleInfoCollector) collect() *externalModuleInfo {
|
||||
hasImportStar := false
|
||||
hasImportDefault := false
|
||||
for _, node := range c.sourceFile.Statements.Nodes {
|
||||
switch node.Kind {
|
||||
case ast.KindImportDeclaration:
|
||||
// import "mod"
|
||||
// import x from "mod"
|
||||
// import * as x from "mod"
|
||||
// import { x, y } from "mod"
|
||||
n := node.AsImportDeclaration()
|
||||
c.addExternalImport(node)
|
||||
if !hasImportStar && getImportNeedsImportStarHelper(n) {
|
||||
hasImportStar = true
|
||||
}
|
||||
if !hasImportDefault && getImportNeedsImportDefaultHelper(n) {
|
||||
hasImportDefault = true
|
||||
}
|
||||
|
||||
case ast.KindImportEqualsDeclaration:
|
||||
n := node.AsImportEqualsDeclaration()
|
||||
if ast.IsExternalModuleReference(n.ModuleReference) {
|
||||
// import x = require("mod")
|
||||
c.addExternalImport(node)
|
||||
}
|
||||
|
||||
case ast.KindExportDeclaration:
|
||||
n := node.AsExportDeclaration()
|
||||
if n.ModuleSpecifier != nil {
|
||||
// export * from "mod"
|
||||
// export * as ns from "mod"
|
||||
// export { x, y } from "mod"
|
||||
c.addExternalImport(node)
|
||||
if n.ExportClause == nil {
|
||||
// export * from "mod"
|
||||
c.output.hasExportStarsToExportValues = true
|
||||
} else if ast.IsNamedExports(n.ExportClause) {
|
||||
// export { x, y } from "mod"
|
||||
c.addExportedNamesForExportDeclaration(n)
|
||||
if !hasImportDefault {
|
||||
hasImportDefault = containsDefaultReference(n.ExportClause)
|
||||
}
|
||||
} else {
|
||||
// export * as ns from "mod"
|
||||
name := n.ExportClause.AsNamespaceExport().Name()
|
||||
nameText := name.Text()
|
||||
if c.addUniqueExport(nameText) {
|
||||
c.addExportedBinding(node, name)
|
||||
c.addExportedName(name)
|
||||
}
|
||||
// we use the same helpers for `export * as ns` as we do for `import * as ns`
|
||||
hasImportStar = true
|
||||
}
|
||||
} else {
|
||||
// export { x, y }
|
||||
c.addExportedNamesForExportDeclaration(node.AsExportDeclaration())
|
||||
}
|
||||
|
||||
case ast.KindExportAssignment:
|
||||
n := node.AsExportAssignment()
|
||||
if n.IsExportEquals && c.output.exportEquals == nil {
|
||||
// export = x
|
||||
c.output.exportEquals = n
|
||||
}
|
||||
|
||||
case ast.KindVariableStatement:
|
||||
n := node.AsVariableStatement()
|
||||
if ast.HasSyntacticModifier(node, ast.ModifierFlagsExport) {
|
||||
for _, decl := range n.DeclarationList.AsVariableDeclarationList().Declarations.Nodes {
|
||||
c.collectExportedVariableInfo(decl)
|
||||
}
|
||||
}
|
||||
|
||||
case ast.KindFunctionDeclaration:
|
||||
n := node.AsFunctionDeclaration()
|
||||
if ast.HasSyntacticModifier(node, ast.ModifierFlagsExport) {
|
||||
c.addExportedFunctionDeclaration(n, nil /*name*/, ast.HasSyntacticModifier(node, ast.ModifierFlagsDefault))
|
||||
}
|
||||
|
||||
case ast.KindClassDeclaration:
|
||||
n := node.AsClassDeclaration()
|
||||
if ast.HasSyntacticModifier(node, ast.ModifierFlagsExport) {
|
||||
if ast.HasSyntacticModifier(node, ast.ModifierFlagsDefault) {
|
||||
// export default class { }
|
||||
if !c.hasExportDefault {
|
||||
name := n.Name()
|
||||
if name == nil {
|
||||
name = c.emitContext.Factory.NewGeneratedNameForNode(node)
|
||||
}
|
||||
c.addExportedBinding(node, name)
|
||||
c.hasExportDefault = true
|
||||
}
|
||||
} else {
|
||||
// export class x { }
|
||||
name := n.Name()
|
||||
if name != nil {
|
||||
if c.addUniqueExport(name.Text()) {
|
||||
c.addExportedBinding(node, name)
|
||||
c.addExportedName(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return c.output
|
||||
}
|
||||
|
||||
func (c *externalModuleInfoCollector) addUniqueExport(name string) bool {
|
||||
if !c.uniqueExports.Has(name) {
|
||||
c.uniqueExports.Add(name)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *externalModuleInfoCollector) addExportedBinding(decl *ast.Declaration, name *ast.ModuleExportName) {
|
||||
c.output.exportedBindings.Add(c.emitContext.MostOriginal(decl), name)
|
||||
}
|
||||
|
||||
func (c *externalModuleInfoCollector) addExternalImport(node *ast.Node /*ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration*/) {
|
||||
c.output.externalImports = append(c.output.externalImports, node)
|
||||
}
|
||||
|
||||
func (c *externalModuleInfoCollector) addExportedName(name *ast.ModuleExportName) {
|
||||
c.output.exportedNames = append(c.output.exportedNames, name)
|
||||
}
|
||||
|
||||
func (c *externalModuleInfoCollector) addExportedNamesForExportDeclaration(node *ast.ExportDeclaration) {
|
||||
for _, specifier := range node.ExportClause.AsNamedExports().Elements.Nodes {
|
||||
specifierNameText := specifier.Name().Text()
|
||||
if c.addUniqueExport(specifierNameText) {
|
||||
name := specifier.PropertyNameOrName()
|
||||
if name.Kind != ast.KindStringLiteral {
|
||||
if node.ModuleSpecifier == nil {
|
||||
c.output.exportSpecifiers.Add(name.Text(), specifier.AsExportSpecifier())
|
||||
}
|
||||
|
||||
decl := c.resolver.GetReferencedImportDeclaration(c.emitContext.MostOriginal(name))
|
||||
if decl == nil {
|
||||
decl = c.resolver.GetReferencedValueDeclaration(c.emitContext.MostOriginal(name))
|
||||
}
|
||||
if decl != nil {
|
||||
if decl.Kind == ast.KindFunctionDeclaration {
|
||||
c.uniqueExports.Delete(specifierNameText)
|
||||
c.addExportedFunctionDeclaration(decl.AsFunctionDeclaration(), specifier.Name(), ast.ModuleExportNameIsDefault(specifier.Name()))
|
||||
continue
|
||||
}
|
||||
c.addExportedBinding(decl, specifier.Name())
|
||||
}
|
||||
}
|
||||
|
||||
c.addExportedName(specifier.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *externalModuleInfoCollector) addExportedFunctionDeclaration(node *ast.FunctionDeclaration, name *ast.ModuleExportName, isDefault bool) {
|
||||
c.output.exportedFunctions.Add(c.emitContext.MostOriginal(node.AsNode()))
|
||||
if isDefault {
|
||||
// export default function() { }
|
||||
// function x() { } + export { x as default };
|
||||
if !c.hasExportDefault {
|
||||
if name == nil {
|
||||
name = c.emitContext.Factory.NewGeneratedNameForNode(node.AsNode())
|
||||
}
|
||||
c.addExportedBinding(node.AsNode(), name)
|
||||
c.hasExportDefault = true
|
||||
}
|
||||
} else {
|
||||
// export function x() { }
|
||||
// function x() { } + export { x }
|
||||
if name == nil {
|
||||
name = node.Name()
|
||||
}
|
||||
nameText := name.Text()
|
||||
if c.addUniqueExport(nameText) {
|
||||
c.addExportedBinding(node.AsNode(), name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *externalModuleInfoCollector) collectExportedVariableInfo(decl *ast.Node /*VariableDeclaration | BindingElement*/) {
|
||||
if ast.IsBindingPattern(decl.Name()) {
|
||||
for _, element := range decl.Name().AsBindingPattern().Elements.Nodes {
|
||||
e := element.AsBindingElement()
|
||||
if e.Name() != nil {
|
||||
c.collectExportedVariableInfo(element)
|
||||
}
|
||||
}
|
||||
} else if !c.emitContext.HasAutoGenerateInfo(decl.Name()) {
|
||||
text := decl.Name().Text()
|
||||
if c.addUniqueExport(text) {
|
||||
c.addExportedName(decl.Name())
|
||||
if transformers.IsLocalName(c.emitContext, decl.Name()) {
|
||||
c.addExportedBinding(decl, decl.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const externalHelpersModuleNameText = "tslib"
|
||||
|
||||
func createExternalHelpersImportDeclarationIfNeeded(emitContext *printer.EmitContext, sourceFile *ast.SourceFile, compilerOptions *core.CompilerOptions, fileModuleKind core.ModuleKind, hasExportStarsToExportValues bool, hasImportStar bool, hasImportDefault bool) *ast.Node /*ImportDeclaration | ImportEqualsDeclaration*/ {
|
||||
if compilerOptions.ImportHelpers.IsTrue() && ast.IsEffectiveExternalModule(sourceFile, compilerOptions) {
|
||||
moduleKind := compilerOptions.GetEmitModuleKind()
|
||||
helpers := getImportedHelpers(emitContext, sourceFile)
|
||||
if fileModuleKind == core.ModuleKindCommonJS || fileModuleKind == core.ModuleKindNone && moduleKind == core.ModuleKindCommonJS {
|
||||
// When we emit to a non-ES module, generate a synthetic `import tslib = require("tslib")` to be further transformed.
|
||||
externalHelpersModuleName := getOrCreateExternalHelpersModuleNameIfNeeded(emitContext, sourceFile, compilerOptions, helpers, hasExportStarsToExportValues, hasImportStar || hasImportDefault, fileModuleKind)
|
||||
if externalHelpersModuleName != nil {
|
||||
externalHelpersImportDeclaration := emitContext.Factory.NewImportEqualsDeclaration(
|
||||
nil, /*modifiers*/
|
||||
false, /*isTypeOnly*/
|
||||
externalHelpersModuleName,
|
||||
emitContext.Factory.NewExternalModuleReference(emitContext.Factory.NewStringLiteral(externalHelpersModuleNameText)),
|
||||
)
|
||||
emitContext.AddEmitFlags(externalHelpersImportDeclaration, printer.EFNeverApplyImportHelper|printer.EFCustomPrologue)
|
||||
return externalHelpersImportDeclaration
|
||||
}
|
||||
} else {
|
||||
// When we emit as an ES module, generate an `import` declaration that uses named imports for helpers.
|
||||
// If we cannot determine the implied module kind under `module: preserve` we assume ESM.
|
||||
var helperNames []string
|
||||
for _, helper := range helpers {
|
||||
importName := helper.ImportName
|
||||
if len(importName) > 0 {
|
||||
helperNames = core.AppendIfUnique(helperNames, importName)
|
||||
}
|
||||
}
|
||||
if len(helperNames) > 0 {
|
||||
slices.SortFunc(helperNames, stringutil.CompareStringsCaseSensitive)
|
||||
// Alias the imports if the names are used somewhere in the file.
|
||||
// NOTE: We don't need to care about global import collisions as this is a module.
|
||||
|
||||
importSpecifiers := core.Map(helperNames, func(name string) *ast.ImportSpecifierNode {
|
||||
if printer.IsFileLevelUniqueName(sourceFile, name, nil /*hasGlobalName*/) {
|
||||
return emitContext.Factory.NewImportSpecifier(false /*isTypeOnly*/, nil /*propertyName*/, emitContext.Factory.NewIdentifier(name))
|
||||
} else {
|
||||
return emitContext.Factory.NewImportSpecifier(false /*isTypeOnly*/, emitContext.Factory.NewIdentifier(name), emitContext.Factory.NewUnscopedHelperName(name))
|
||||
}
|
||||
})
|
||||
namedBindings := emitContext.Factory.NewNamedImports(emitContext.Factory.NewNodeList(importSpecifiers))
|
||||
parseNode := emitContext.MostOriginal(sourceFile.AsNode())
|
||||
emitContext.AddEmitFlags(parseNode, printer.EFExternalHelpers)
|
||||
|
||||
externalHelpersImportDeclaration := emitContext.Factory.NewImportDeclaration(
|
||||
nil, /*modifiers*/
|
||||
emitContext.Factory.NewImportClause(ast.KindUnknown /*phaseModifier*/, nil /*name*/, namedBindings),
|
||||
emitContext.Factory.NewStringLiteral(externalHelpersModuleNameText),
|
||||
nil, /*attributes*/
|
||||
)
|
||||
|
||||
emitContext.AddEmitFlags(externalHelpersImportDeclaration, printer.EFNeverApplyImportHelper|printer.EFCustomPrologue)
|
||||
return externalHelpersImportDeclaration
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getImportedHelpers(emitContext *printer.EmitContext, sourceFile *ast.SourceFile) []*printer.EmitHelper {
|
||||
var helpers []*printer.EmitHelper
|
||||
for _, helper := range emitContext.GetEmitHelpers(sourceFile.AsNode()) {
|
||||
if !helper.Scoped {
|
||||
helpers = append(helpers, helper)
|
||||
}
|
||||
}
|
||||
return helpers
|
||||
}
|
||||
|
||||
func getOrCreateExternalHelpersModuleNameIfNeeded(emitContext *printer.EmitContext, node *ast.SourceFile, compilerOptions *core.CompilerOptions, helpers []*printer.EmitHelper, hasExportStarsToExportValues bool, hasImportStarOrImportDefault bool, fileModuleKind core.ModuleKind) *ast.IdentifierNode {
|
||||
externalHelpersModuleName := emitContext.GetExternalHelpersModuleName(node)
|
||||
if externalHelpersModuleName != nil {
|
||||
return externalHelpersModuleName
|
||||
}
|
||||
|
||||
create := len(helpers) > 0 ||
|
||||
(hasExportStarsToExportValues || compilerOptions.GetESModuleInterop() && hasImportStarOrImportDefault) &&
|
||||
fileModuleKind < core.ModuleKindSystem
|
||||
|
||||
if create {
|
||||
externalHelpersModuleName = emitContext.Factory.NewUniqueName(externalHelpersModuleNameText)
|
||||
emitContext.SetExternalHelpersModuleName(node, externalHelpersModuleName)
|
||||
}
|
||||
|
||||
return externalHelpersModuleName
|
||||
}
|
||||
|
||||
func isNamedDefaultReference(e *ast.Node /*ImportSpecifier | ExportSpecifier*/) bool {
|
||||
return ast.ModuleExportNameIsDefault(e.PropertyNameOrName())
|
||||
}
|
||||
|
||||
func containsDefaultReference(node *ast.Node /*NamedImportBindings | NamedExportBindings*/) bool {
|
||||
if node == nil {
|
||||
return false
|
||||
}
|
||||
var elements *ast.NodeList
|
||||
switch {
|
||||
case ast.IsNamedImports(node):
|
||||
elements = node.AsNamedImports().Elements
|
||||
case ast.IsNamedExports(node):
|
||||
elements = node.AsNamedExports().Elements
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return core.Some(elements.Nodes, isNamedDefaultReference)
|
||||
}
|
||||
|
||||
func getExportNeedsImportStarHelper(node *ast.ExportDeclaration) bool {
|
||||
return ast.GetNamespaceDeclarationNode(node.AsNode()) != nil
|
||||
}
|
||||
|
||||
func getImportNeedsImportStarHelper(node *ast.ImportDeclaration) bool {
|
||||
if ast.GetNamespaceDeclarationNode(node.AsNode()) != nil {
|
||||
return true
|
||||
}
|
||||
if node.ImportClause == nil {
|
||||
return false
|
||||
}
|
||||
bindings := node.ImportClause.AsImportClause().NamedBindings
|
||||
if bindings == nil {
|
||||
return false
|
||||
}
|
||||
if !ast.IsNamedImports(bindings) {
|
||||
return false
|
||||
}
|
||||
namedImports := bindings.AsNamedImports()
|
||||
defaultRefCount := 0
|
||||
for _, binding := range namedImports.Elements.Nodes {
|
||||
if isNamedDefaultReference(binding) {
|
||||
defaultRefCount++
|
||||
}
|
||||
}
|
||||
// Import star is required if there's default named refs mixed with non-default refs, or if theres non-default refs and it has a default import
|
||||
return (defaultRefCount > 0 && defaultRefCount != len(namedImports.Elements.Nodes)) || ((len(namedImports.Elements.Nodes)-defaultRefCount) != 0 && ast.IsDefaultImport(node.AsNode()))
|
||||
}
|
||||
|
||||
func getImportNeedsImportDefaultHelper(node *ast.ImportDeclaration) bool {
|
||||
// Import default is needed if there's a default import or a default ref and no other refs (meaning an import star helper wasn't requested)
|
||||
return !getImportNeedsImportStarHelper(node) && (ast.IsDefaultImport(node.AsNode()) || (node.ImportClause != nil &&
|
||||
ast.IsNamedImports(node.ImportClause.AsImportClause().NamedBindings) &&
|
||||
containsDefaultReference(node.ImportClause.AsImportClause().NamedBindings)))
|
||||
}
|
||||
@ -1,58 +0,0 @@
|
||||
package moduletransforms
|
||||
|
||||
import (
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/binder"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers"
|
||||
)
|
||||
|
||||
type ImpliedModuleTransformer struct {
|
||||
transformers.Transformer
|
||||
opts *transformers.TransformOptions
|
||||
resolver binder.ReferenceResolver
|
||||
getEmitModuleFormatOfFile func(file ast.HasFileName) core.ModuleKind
|
||||
cjsTransformer *transformers.Transformer
|
||||
esmTransformer *transformers.Transformer
|
||||
}
|
||||
|
||||
func NewImpliedModuleTransformer(opts *transformers.TransformOptions) *transformers.Transformer {
|
||||
compilerOptions := opts.CompilerOptions
|
||||
resolver := opts.Resolver
|
||||
if resolver == nil {
|
||||
resolver = binder.NewReferenceResolver(compilerOptions, binder.ReferenceResolverHooks{})
|
||||
}
|
||||
tx := &ImpliedModuleTransformer{opts: opts, resolver: resolver, getEmitModuleFormatOfFile: opts.GetEmitModuleFormatOfFile}
|
||||
return tx.NewTransformer(tx.visit, opts.Context)
|
||||
}
|
||||
|
||||
func (tx *ImpliedModuleTransformer) visit(node *ast.Node) *ast.Node {
|
||||
switch node.Kind {
|
||||
case ast.KindSourceFile:
|
||||
node = tx.visitSourceFile(node.AsSourceFile())
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
func (tx *ImpliedModuleTransformer) visitSourceFile(node *ast.SourceFile) *ast.Node {
|
||||
if node.IsDeclarationFile {
|
||||
return node.AsNode()
|
||||
}
|
||||
|
||||
format := tx.getEmitModuleFormatOfFile(node)
|
||||
|
||||
var transformer *transformers.Transformer
|
||||
if format >= core.ModuleKindES2015 {
|
||||
if tx.esmTransformer == nil {
|
||||
tx.esmTransformer = NewESModuleTransformer(tx.opts)
|
||||
}
|
||||
transformer = tx.esmTransformer
|
||||
} else {
|
||||
if tx.cjsTransformer == nil {
|
||||
tx.cjsTransformer = NewCommonJSModuleTransformer(tx.opts)
|
||||
}
|
||||
transformer = tx.cjsTransformer
|
||||
}
|
||||
|
||||
return transformer.TransformSourceFile(node).AsNode()
|
||||
}
|
||||
@ -1,119 +0,0 @@
|
||||
package moduletransforms
|
||||
|
||||
import (
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/outputpaths"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
|
||||
)
|
||||
|
||||
func isDeclarationNameOfEnumOrNamespace(emitContext *printer.EmitContext, node *ast.IdentifierNode) bool {
|
||||
if original := emitContext.MostOriginal(node); original != nil && original.Parent != nil {
|
||||
switch original.Parent.Kind {
|
||||
case ast.KindEnumDeclaration, ast.KindModuleDeclaration:
|
||||
return original == original.Parent.Name()
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func rewriteModuleSpecifier(emitContext *printer.EmitContext, node *ast.Expression, compilerOptions *core.CompilerOptions) *ast.Expression {
|
||||
if node == nil || !ast.IsStringLiteral(node) || !core.ShouldRewriteModuleSpecifier(node.Text(), compilerOptions) {
|
||||
return node
|
||||
}
|
||||
updatedText := tspath.ChangeExtension(node.Text(), outputpaths.GetOutputExtension(node.Text(), compilerOptions.Jsx))
|
||||
if updatedText != node.Text() {
|
||||
updated := emitContext.Factory.NewStringLiteral(updatedText)
|
||||
// !!! set quote style
|
||||
emitContext.SetOriginal(updated, node)
|
||||
emitContext.AssignCommentAndSourceMapRanges(updated, node)
|
||||
return updated
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
func createEmptyImports(factory *printer.NodeFactory) *ast.Statement {
|
||||
return factory.NewExportDeclaration(
|
||||
nil, /*modifiers*/
|
||||
false, /*isTypeOnly*/
|
||||
factory.NewNamedExports(factory.NewNodeList(nil)),
|
||||
nil, /*moduleSpecifier*/
|
||||
nil, /*attributes*/
|
||||
)
|
||||
}
|
||||
|
||||
// Get the name of a target module from an import/export declaration as should be written in the emitted output.
|
||||
// The emitted output name can be different from the input if:
|
||||
// 1. The module has a /// <amd-module name="<new name>" />
|
||||
// 2. --out or --outFile is used, making the name relative to the rootDir
|
||||
// 3- The containing SourceFile has an entry in renamedDependencies for the import as requested by some module loaders (e.g. System).
|
||||
//
|
||||
// Otherwise, a new StringLiteral node representing the module name will be returned.
|
||||
func getExternalModuleNameLiteral(factory *printer.NodeFactory, importNode *ast.Node /*ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration | ImportCall*/, sourceFile *ast.SourceFile, host any /*EmitHost*/, resolver printer.EmitResolver, compilerOptions *core.CompilerOptions) *ast.StringLiteralNode {
|
||||
moduleName := ast.GetExternalModuleName(importNode)
|
||||
if moduleName != nil && ast.IsStringLiteral(moduleName) {
|
||||
name := tryGetModuleNameFromDeclaration(importNode, host, factory, resolver, compilerOptions)
|
||||
if name == nil {
|
||||
name = tryRenameExternalModule(factory, moduleName, sourceFile)
|
||||
}
|
||||
if name == nil {
|
||||
name = factory.NewStringLiteral(moduleName.Text())
|
||||
}
|
||||
return name
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get the name of a module as should be written in the emitted output.
|
||||
// The emitted output name can be different from the input if:
|
||||
// 1. The module has a /// <amd-module name="<new name>" />
|
||||
// 2. --out or --outFile is used, making the name relative to the rootDir
|
||||
//
|
||||
// Otherwise, a new StringLiteral node representing the module name will be returned.
|
||||
func tryGetModuleNameFromFile(factory *printer.NodeFactory, file *ast.SourceFile, host any /*EmitHost*/, options *core.CompilerOptions) *ast.StringLiteralNode {
|
||||
if file == nil {
|
||||
return nil
|
||||
}
|
||||
// !!!
|
||||
// if file.moduleName {
|
||||
// return factory.createStringLiteral(file.moduleName)
|
||||
// }
|
||||
return nil
|
||||
}
|
||||
|
||||
func tryGetModuleNameFromDeclaration(declaration *ast.Node /*ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ImportCall*/, host any /*EmitHost*/, factory *printer.NodeFactory, resolver printer.EmitResolver, compilerOptions *core.CompilerOptions) *ast.StringLiteralNode {
|
||||
if resolver == nil {
|
||||
return nil
|
||||
}
|
||||
return tryGetModuleNameFromFile(factory, resolver.GetExternalModuleFileFromDeclaration(declaration), host, compilerOptions)
|
||||
}
|
||||
|
||||
// Resolves a local path to a path which is absolute to the base of the emit
|
||||
func getExternalModuleNameFromPath(host any /*ResolveModuleNameResolutionHost*/, fileName string, referencePath string) string {
|
||||
// !!!
|
||||
return ""
|
||||
}
|
||||
|
||||
// Some bundlers (SystemJS builder) sometimes want to rename dependencies.
|
||||
// Here we check if alternative name was provided for a given moduleName and return it if possible.
|
||||
func tryRenameExternalModule(factory *printer.NodeFactory, moduleName *ast.LiteralExpression, sourceFile *ast.SourceFile) *ast.StringLiteralNode {
|
||||
// !!!
|
||||
return nil
|
||||
}
|
||||
|
||||
func isFileLevelReservedGeneratedIdentifier(emitContext *printer.EmitContext, name *ast.IdentifierNode) bool {
|
||||
info := emitContext.GetAutoGenerateInfo(name)
|
||||
return info != nil &&
|
||||
info.Flags.IsFileLevel() &&
|
||||
info.Flags.IsOptimistic() &&
|
||||
info.Flags.IsReservedInNestedScopes()
|
||||
}
|
||||
|
||||
// A simple inlinable expression is an expression which can be copied into multiple locations
|
||||
// without risk of repeating any sideeffects and whose value could not possibly change between
|
||||
// any such locations
|
||||
func isSimpleInlineableExpression(expression *ast.Expression) bool {
|
||||
return !ast.IsIdentifier(expression) && transformers.IsSimpleCopiableExpression(expression)
|
||||
}
|
||||
@ -1,41 +0,0 @@
|
||||
package transformers
|
||||
|
||||
import (
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
|
||||
)
|
||||
|
||||
type Transformer struct {
|
||||
emitContext *printer.EmitContext
|
||||
factory *printer.NodeFactory
|
||||
visitor *ast.NodeVisitor
|
||||
}
|
||||
|
||||
func (tx *Transformer) NewTransformer(visit func(node *ast.Node) *ast.Node, emitContext *printer.EmitContext) *Transformer {
|
||||
if tx.emitContext != nil {
|
||||
panic("Transformer already initialized")
|
||||
}
|
||||
if emitContext == nil {
|
||||
emitContext = printer.NewEmitContext()
|
||||
}
|
||||
tx.emitContext = emitContext
|
||||
tx.factory = emitContext.Factory
|
||||
tx.visitor = emitContext.NewNodeVisitor(visit)
|
||||
return tx
|
||||
}
|
||||
|
||||
func (tx *Transformer) EmitContext() *printer.EmitContext {
|
||||
return tx.emitContext
|
||||
}
|
||||
|
||||
func (tx *Transformer) Visitor() *ast.NodeVisitor {
|
||||
return tx.visitor
|
||||
}
|
||||
|
||||
func (tx *Transformer) Factory() *printer.NodeFactory {
|
||||
return tx.factory
|
||||
}
|
||||
|
||||
func (tx *Transformer) TransformSourceFile(file *ast.SourceFile) *ast.SourceFile {
|
||||
return tx.visitor.VisitSourceFile(file)
|
||||
}
|
||||
@ -1,205 +0,0 @@
|
||||
package tstransforms
|
||||
|
||||
import (
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers"
|
||||
)
|
||||
|
||||
type ImportElisionTransformer struct {
|
||||
transformers.Transformer
|
||||
compilerOptions *core.CompilerOptions
|
||||
currentSourceFile *ast.SourceFile
|
||||
emitResolver printer.EmitResolver
|
||||
}
|
||||
|
||||
func NewImportElisionTransformer(opt *transformers.TransformOptions) *transformers.Transformer {
|
||||
compilerOptions := opt.CompilerOptions
|
||||
emitContext := opt.Context
|
||||
if compilerOptions.VerbatimModuleSyntax.IsTrue() {
|
||||
panic("ImportElisionTransformer should not be used with VerbatimModuleSyntax")
|
||||
}
|
||||
tx := &ImportElisionTransformer{compilerOptions: compilerOptions, emitResolver: opt.EmitResolver}
|
||||
return tx.NewTransformer(tx.visit, emitContext)
|
||||
}
|
||||
|
||||
func (tx *ImportElisionTransformer) visit(node *ast.Node) *ast.Node {
|
||||
switch node.Kind {
|
||||
case ast.KindImportEqualsDeclaration:
|
||||
if !tx.isElisionBlocked(node) && !tx.shouldEmitImportEqualsDeclaration(node.AsImportEqualsDeclaration()) {
|
||||
return nil
|
||||
}
|
||||
return tx.Visitor().VisitEachChild(node)
|
||||
case ast.KindImportDeclaration:
|
||||
if !tx.isElisionBlocked(node) {
|
||||
n := node.AsImportDeclaration()
|
||||
// Do not elide a side-effect only import declaration.
|
||||
// import "foo";
|
||||
if n.ImportClause != nil {
|
||||
importClause := tx.Visitor().VisitNode(n.ImportClause)
|
||||
if importClause == nil {
|
||||
return nil
|
||||
}
|
||||
return tx.Factory().UpdateImportDeclaration(n, n.Modifiers(), importClause, n.ModuleSpecifier, tx.Visitor().VisitNode(n.Attributes))
|
||||
}
|
||||
}
|
||||
return tx.Visitor().VisitEachChild(node)
|
||||
case ast.KindImportClause:
|
||||
n := node.AsImportClause()
|
||||
name := core.IfElse(tx.shouldEmitAliasDeclaration(node), n.Name(), nil)
|
||||
namedBindings := tx.Visitor().VisitNode(n.NamedBindings)
|
||||
if name == nil && namedBindings == nil {
|
||||
// all import bindings were elided
|
||||
return nil
|
||||
}
|
||||
return tx.Factory().UpdateImportClause(n, n.PhaseModifier, name, namedBindings)
|
||||
case ast.KindNamespaceImport:
|
||||
if !tx.shouldEmitAliasDeclaration(node) {
|
||||
// elide unused imports
|
||||
return nil
|
||||
}
|
||||
return node
|
||||
case ast.KindNamedImports:
|
||||
n := node.AsNamedImports()
|
||||
elements := tx.Visitor().VisitNodes(n.Elements)
|
||||
if len(elements.Nodes) == 0 {
|
||||
// all import specifiers were elided
|
||||
return nil
|
||||
}
|
||||
return tx.Factory().UpdateNamedImports(n, elements)
|
||||
case ast.KindImportSpecifier:
|
||||
if !tx.shouldEmitAliasDeclaration(node) {
|
||||
// elide type-only or unused imports
|
||||
return nil
|
||||
}
|
||||
return node
|
||||
case ast.KindExportAssignment:
|
||||
if !tx.isElisionBlocked(node) && !tx.compilerOptions.VerbatimModuleSyntax.IsTrue() && !tx.isValueAliasDeclaration(node) {
|
||||
// elide unused import
|
||||
return nil
|
||||
}
|
||||
return tx.Visitor().VisitEachChild(node)
|
||||
case ast.KindExportDeclaration:
|
||||
if !tx.isElisionBlocked(node) {
|
||||
n := node.AsExportDeclaration()
|
||||
var exportClause *ast.Node
|
||||
if n.ExportClause != nil {
|
||||
exportClause = tx.Visitor().VisitNode(n.ExportClause)
|
||||
if exportClause == nil {
|
||||
// all export bindings were elided
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return tx.Factory().UpdateExportDeclaration(n, nil /*modifiers*/, false /*isTypeOnly*/, exportClause, tx.Visitor().VisitNode(n.ModuleSpecifier), tx.Visitor().VisitNode(n.Attributes))
|
||||
}
|
||||
return tx.Visitor().VisitEachChild(node)
|
||||
case ast.KindNamedExports:
|
||||
n := node.AsNamedExports()
|
||||
elements := tx.Visitor().VisitNodes(n.Elements)
|
||||
if len(elements.Nodes) == 0 {
|
||||
// all export specifiers were elided
|
||||
return nil
|
||||
}
|
||||
return tx.Factory().UpdateNamedExports(n, elements)
|
||||
case ast.KindExportSpecifier:
|
||||
if !tx.isValueAliasDeclaration(node) {
|
||||
// elide unused export
|
||||
return nil
|
||||
}
|
||||
return node
|
||||
case ast.KindSourceFile:
|
||||
savedCurrentSourceFile := tx.currentSourceFile
|
||||
tx.currentSourceFile = node.AsSourceFile()
|
||||
node = tx.Visitor().VisitEachChild(node)
|
||||
tx.currentSourceFile = savedCurrentSourceFile
|
||||
return node
|
||||
default:
|
||||
return node
|
||||
}
|
||||
}
|
||||
|
||||
func (tx *ImportElisionTransformer) shouldEmitAliasDeclaration(node *ast.Node) bool {
|
||||
return ast.IsInJSFile(node) || tx.isReferencedAliasDeclaration(node)
|
||||
}
|
||||
|
||||
func (tx *ImportElisionTransformer) shouldEmitImportEqualsDeclaration(node *ast.ImportEqualsDeclaration) bool {
|
||||
if !tx.shouldEmitAliasDeclaration(node.AsNode()) {
|
||||
return false
|
||||
}
|
||||
if node.ModuleReference.Kind == ast.KindExternalModuleReference {
|
||||
return true
|
||||
}
|
||||
// preserve old compiler's behavior: emit import declaration (even if we do not consider them referenced) when
|
||||
// - current file is not external module
|
||||
// - import declaration is top level and target is value imported by entity name
|
||||
return tx.currentSourceFile != nil && ast.IsExternalModule(tx.currentSourceFile) && tx.isTopLevelValueImportEqualsWithEntityName(node.AsNode())
|
||||
}
|
||||
|
||||
func (tx *ImportElisionTransformer) isReferencedAliasDeclaration(node *ast.Node) bool {
|
||||
node = tx.EmitContext().ParseNode(node)
|
||||
return node == nil || tx.emitResolver.IsReferencedAliasDeclaration(node)
|
||||
}
|
||||
|
||||
func (tx *ImportElisionTransformer) isValueAliasDeclaration(node *ast.Node) bool {
|
||||
node = tx.EmitContext().ParseNode(node)
|
||||
return node == nil || tx.emitResolver.IsValueAliasDeclaration(node)
|
||||
}
|
||||
|
||||
func (tx *ImportElisionTransformer) isTopLevelValueImportEqualsWithEntityName(node *ast.Node) bool {
|
||||
node = tx.EmitContext().ParseNode(node)
|
||||
return node != nil && tx.emitResolver.IsTopLevelValueImportEqualsWithEntityName(node)
|
||||
}
|
||||
|
||||
// Determines whether import/export elision is blocked for this statement.
|
||||
//
|
||||
// @description
|
||||
// We generally block import/export elision if the statement was modified by a `before` custom
|
||||
// transform, although we will continue to allow it if the statement hasn't replaced a node of a different kind and
|
||||
// as long as the local bindings for the declarations are unchanged.
|
||||
func (tx *ImportElisionTransformer) isElisionBlocked(node *ast.Node /*ImportDeclaration | ImportEqualsDeclaration | ExportAssignment | ExportDeclaration*/) bool {
|
||||
parsed := tx.EmitContext().ParseNode(node)
|
||||
if parsed == node || ast.IsExportAssignment(node) {
|
||||
return false
|
||||
}
|
||||
|
||||
if parsed == nil || parsed.Kind != node.Kind {
|
||||
// no longer safe to elide as the declaration was replaced with a node of a different kind
|
||||
return true
|
||||
}
|
||||
|
||||
switch node.Kind {
|
||||
case ast.KindImportDeclaration:
|
||||
n := node.AsImportDeclaration()
|
||||
p := parsed.AsImportDeclaration()
|
||||
if n.ImportClause != p.ImportClause {
|
||||
return true // no longer safe to elide as the import clause has changed
|
||||
}
|
||||
if n.Attributes != p.Attributes {
|
||||
return true // no longer safe to elide as the import attributes have changed
|
||||
}
|
||||
case ast.KindImportEqualsDeclaration:
|
||||
n := node.AsImportEqualsDeclaration()
|
||||
p := parsed.AsImportEqualsDeclaration()
|
||||
if n.Name() != p.Name() {
|
||||
return true // no longer safe to elide as local binding has changed
|
||||
}
|
||||
if n.IsTypeOnly != p.IsTypeOnly {
|
||||
return true // no longer safe to elide as `type` modifier has changed
|
||||
}
|
||||
if n.ModuleReference != p.ModuleReference && (ast.IsEntityName(n.ModuleReference) || ast.IsEntityName(p.ModuleReference)) {
|
||||
return true // no longer safe to elide as EntityName reference has changed.
|
||||
}
|
||||
case ast.KindExportDeclaration:
|
||||
n := node.AsExportDeclaration()
|
||||
p := parsed.AsExportDeclaration()
|
||||
if n.ExportClause != p.ExportClause {
|
||||
return true // no longer safe to elide as the export clause has changed
|
||||
}
|
||||
if n.Attributes != p.Attributes {
|
||||
return true // no longer safe to elide as the export attributes have changed
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
@ -1,258 +0,0 @@
|
||||
package tstransforms_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/binder"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/checker"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/module"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/modulespecifiers"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/testutil/emittestutil"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/testutil/parsetestutil"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers/tstransforms"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/tsoptions"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
|
||||
)
|
||||
|
||||
type fakeProgram struct {
|
||||
singleThreaded bool
|
||||
compilerOptions *core.CompilerOptions
|
||||
files []*ast.SourceFile
|
||||
getEmitModuleFormatOfFile func(sourceFile ast.HasFileName) core.ModuleKind
|
||||
getImpliedNodeFormatForEmit func(sourceFile ast.HasFileName) core.ModuleKind
|
||||
getResolvedModule func(currentSourceFile ast.HasFileName, moduleReference string, mode core.ResolutionMode) *module.ResolvedModule
|
||||
getSourceFile func(FileName string) *ast.SourceFile
|
||||
getSourceFileForResolvedModule func(FileName string) *ast.SourceFile
|
||||
}
|
||||
|
||||
// GetRedirectForResolution implements checker.Program.
|
||||
func (p *fakeProgram) GetRedirectForResolution(file ast.HasFileName) *tsoptions.ParsedCommandLine {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// SourceFileMayBeEmitted implements checker.Program.
|
||||
func (p *fakeProgram) SourceFileMayBeEmitted(sourceFile *ast.SourceFile, forceDtsEmit bool) bool {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// GetEmitSyntaxForUsageLocation implements checker.Program.
|
||||
func (p *fakeProgram) GetEmitSyntaxForUsageLocation(sourceFile ast.HasFileName, usageLocation *ast.StringLiteralLike) core.ResolutionMode {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// CommonSourceDirectory implements checker.Program.
|
||||
func (p *fakeProgram) CommonSourceDirectory() string {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
func (p *fakeProgram) GetResolvedModuleFromModuleSpecifier(file ast.HasFileName, moduleSpecifier *ast.StringLiteralLike) *module.ResolvedModule {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
func (p *fakeProgram) FileExists(path string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *fakeProgram) GetCurrentDirectory() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *fakeProgram) GetGlobalTypingsCacheLocation() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *fakeProgram) GetNearestAncestorDirectoryWithPackageJson(dirname string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *fakeProgram) GetPackageJsonInfo(pkgJsonPath string) modulespecifiers.PackageJsonInfo {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *fakeProgram) GetRedirectTargets(path tspath.Path) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *fakeProgram) GetSourceOfProjectReferenceIfOutputIncluded(file ast.HasFileName) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *fakeProgram) GetProjectReferenceFromSource(path tspath.Path) *tsoptions.SourceOutputAndProjectReference {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *fakeProgram) IsSourceFromProjectReference(path tspath.Path) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *fakeProgram) GetProjectReferenceFromOutputDts(path tspath.Path) *tsoptions.SourceOutputAndProjectReference {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *fakeProgram) UseCaseSensitiveFileNames() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *fakeProgram) Options() *core.CompilerOptions {
|
||||
return p.compilerOptions
|
||||
}
|
||||
|
||||
func (p *fakeProgram) SourceFiles() []*ast.SourceFile {
|
||||
return p.files
|
||||
}
|
||||
|
||||
func (p *fakeProgram) BindSourceFiles() {
|
||||
wg := core.NewWorkGroup(p.singleThreaded)
|
||||
for _, file := range p.files {
|
||||
if !file.IsBound() {
|
||||
wg.Queue(func() {
|
||||
binder.BindSourceFile(file)
|
||||
})
|
||||
}
|
||||
}
|
||||
wg.RunAndWait()
|
||||
}
|
||||
|
||||
func (p *fakeProgram) GetEmitModuleFormatOfFile(sourceFile ast.HasFileName) core.ModuleKind {
|
||||
return p.getEmitModuleFormatOfFile(sourceFile)
|
||||
}
|
||||
|
||||
func (p *fakeProgram) GetImpliedNodeFormatForEmit(sourceFile ast.HasFileName) core.ModuleKind {
|
||||
return p.getImpliedNodeFormatForEmit(sourceFile)
|
||||
}
|
||||
|
||||
func (p *fakeProgram) GetDefaultResolutionModeForFile(sourceFile ast.HasFileName) core.ResolutionMode {
|
||||
return p.getEmitModuleFormatOfFile(sourceFile)
|
||||
}
|
||||
|
||||
func (p *fakeProgram) GetModeForUsageLocation(sourceFile ast.HasFileName, location *ast.Node) core.ResolutionMode {
|
||||
return p.getEmitModuleFormatOfFile(sourceFile)
|
||||
}
|
||||
|
||||
func (p *fakeProgram) GetResolvedModule(currentSourceFile ast.HasFileName, moduleReference string, mode core.ResolutionMode) *module.ResolvedModule {
|
||||
return p.getResolvedModule(currentSourceFile, moduleReference, mode)
|
||||
}
|
||||
|
||||
func (p *fakeProgram) GetSourceFile(FileName string) *ast.SourceFile {
|
||||
return p.getSourceFile(FileName)
|
||||
}
|
||||
|
||||
func (p *fakeProgram) GetSourceFileForResolvedModule(FileName string) *ast.SourceFile {
|
||||
return p.getSourceFileForResolvedModule(FileName)
|
||||
}
|
||||
|
||||
func (p *fakeProgram) GetSourceFileMetaData(path tspath.Path) ast.SourceFileMetaData {
|
||||
return ast.SourceFileMetaData{}
|
||||
}
|
||||
|
||||
func (p *fakeProgram) GetImportHelpersImportSpecifier(path tspath.Path) *ast.Node {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *fakeProgram) GetJSXRuntimeImportSpecifier(path tspath.Path) (moduleReference string, specifier *ast.Node) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (p *fakeProgram) GetResolvedModules() map[tspath.Path]module.ModeAwareCache[*module.ResolvedModule] {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
func (p *fakeProgram) IsSourceFileDefaultLibrary(path tspath.Path) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func TestImportElision(t *testing.T) {
|
||||
t.Parallel()
|
||||
data := []struct {
|
||||
title string
|
||||
input string
|
||||
output string
|
||||
other string
|
||||
jsx bool
|
||||
}{
|
||||
{title: "ImportEquals#1", input: "import x = require(\"other\"); x;", output: "import x = require(\"other\");\nx;"},
|
||||
{title: "ImportEquals#2", input: "import x = require(\"other\");", output: ""},
|
||||
{title: "ImportDeclaration#1", input: `import "m";`, output: `import "m";`},
|
||||
{title: "ImportDeclaration#2", input: "import * as x from \"other\"; x;", output: "import * as x from \"other\";\nx;"},
|
||||
{title: "ImportDeclaration#3", input: "import x from \"other\"; x;", output: "import x from \"other\";\nx;"},
|
||||
{title: "ImportDeclaration#4", input: "import { x } from \"other\"; x;", output: "import { x } from \"other\";\nx;"},
|
||||
{title: "ImportDeclaration#5", input: "import * as x from \"other\";", output: ""},
|
||||
{title: "ImportDeclaration#6", input: "import x from \"other\";", output: ""},
|
||||
{title: "ImportDeclaration#7", input: "import { x } from \"other\";", output: ""},
|
||||
{title: "ExportDeclaration#1", input: "export * from \"other\";", other: "export let x;", output: "export * from \"other\";"},
|
||||
{title: "ExportDeclaration#2", input: "export * as x from \"other\";", other: "export let x;", output: "export * as x from \"other\";"},
|
||||
{title: "ExportDeclaration#3", input: "export * from \"other\";", other: "export let x;", output: "export * from \"other\";"},
|
||||
{title: "ExportDeclaration#4", input: "export * as x from \"other\";", other: "export let x;", output: "export * as x from \"other\";"},
|
||||
{title: "ExportDeclaration#5", input: "export { x } from \"other\";", other: "export let x;", output: "export { x } from \"other\";"},
|
||||
{title: "ExportDeclaration#6", input: "export { x } from \"other\";", other: "export type x = any;", output: ""},
|
||||
{title: "ExportDeclaration#7", input: "export { x }; let x;", output: "export { x };\nlet x;"},
|
||||
{title: "ExportDeclaration#8", input: "export { x }; type x = any;", output: ""},
|
||||
{title: "ExportDeclaration#9", input: "import { x } from \"other\"; export { x };", other: "export type x = any;", output: ""},
|
||||
{title: "ExportAssignment#1", input: "let x; export default x;", output: "let x;\nexport default x;"},
|
||||
{title: "ExportAssignment#2", input: "type x = any; export default x;", output: ""},
|
||||
}
|
||||
|
||||
for _, rec := range data {
|
||||
t.Run(rec.title, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
file := parsetestutil.ParseTypeScript(rec.input, rec.jsx)
|
||||
parsetestutil.CheckDiagnostics(t, file)
|
||||
files := []*ast.SourceFile{file}
|
||||
|
||||
var other *ast.SourceFile
|
||||
if len(rec.other) > 0 {
|
||||
other = parsetestutil.ParseTypeScript(rec.other, rec.jsx)
|
||||
parsetestutil.CheckDiagnostics(t, other)
|
||||
files = append(files, other)
|
||||
}
|
||||
|
||||
compilerOptions := &core.CompilerOptions{}
|
||||
|
||||
c := checker.NewChecker(&fakeProgram{
|
||||
singleThreaded: true,
|
||||
compilerOptions: compilerOptions,
|
||||
files: files,
|
||||
getEmitModuleFormatOfFile: func(sourceFile ast.HasFileName) core.ModuleKind {
|
||||
return core.ModuleKindESNext
|
||||
},
|
||||
getImpliedNodeFormatForEmit: func(sourceFile ast.HasFileName) core.ModuleKind {
|
||||
return core.ModuleKindESNext
|
||||
},
|
||||
getSourceFile: func(fileName string) *ast.SourceFile {
|
||||
if fileName == "other.ts" {
|
||||
return other
|
||||
}
|
||||
return nil
|
||||
},
|
||||
getSourceFileForResolvedModule: func(fileName string) *ast.SourceFile {
|
||||
if fileName == "other.ts" {
|
||||
return other
|
||||
}
|
||||
return nil
|
||||
},
|
||||
getResolvedModule: func(currentSourceFile ast.HasFileName, moduleReference string, mode core.ResolutionMode) *module.ResolvedModule {
|
||||
if currentSourceFile == file && moduleReference == "other" {
|
||||
return &module.ResolvedModule{
|
||||
ResolvedFileName: "other.ts",
|
||||
Extension: tspath.ExtensionTs,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
emitResolver := c.GetEmitResolver()
|
||||
emitResolver.MarkLinkedReferencesRecursively(file)
|
||||
|
||||
opts := &transformers.TransformOptions{CompilerOptions: compilerOptions, Context: printer.NewEmitContext(), EmitResolver: emitResolver, Resolver: emitResolver}
|
||||
file = tstransforms.NewTypeEraserTransformer(opts).TransformSourceFile(file)
|
||||
file = tstransforms.NewImportElisionTransformer(opts).TransformSourceFile(file)
|
||||
emittestutil.CheckEmit(t, nil, file, rec.output)
|
||||
})
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,445 +0,0 @@
|
||||
package tstransforms_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/binder"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/testutil/emittestutil"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/testutil/parsetestutil"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers/tstransforms"
|
||||
)
|
||||
|
||||
func TestEnumTransformer(t *testing.T) {
|
||||
t.Parallel()
|
||||
data := []struct {
|
||||
title string
|
||||
input string
|
||||
output string
|
||||
}{
|
||||
{title: "empty enum", input: "enum E {}", output: `var E;
|
||||
(function (E) {
|
||||
})(E || (E = {}));`},
|
||||
|
||||
{title: "simple enum", input: "enum E {A}", output: `var E;
|
||||
(function (E) {
|
||||
E[E["A"] = 0] = "A";
|
||||
})(E || (E = {}));`},
|
||||
|
||||
{title: "autonumber enum #1", input: "enum E {A,B}", output: `var E;
|
||||
(function (E) {
|
||||
E[E["A"] = 0] = "A";
|
||||
E[E["B"] = 1] = "B";
|
||||
})(E || (E = {}));`},
|
||||
|
||||
{title: "autonumber enum #2", input: "enum E {A = 1,B}", output: `var E;
|
||||
(function (E) {
|
||||
E[E["A"] = 1] = "A";
|
||||
E[E["B"] = 2] = "B";
|
||||
})(E || (E = {}));`},
|
||||
|
||||
{title: "autonumber enum #3", input: "enum E {A = 1,B,C}", output: `var E;
|
||||
(function (E) {
|
||||
E[E["A"] = 1] = "A";
|
||||
E[E["B"] = 2] = "B";
|
||||
E[E["C"] = 3] = "C";
|
||||
})(E || (E = {}));`},
|
||||
|
||||
{title: "autonumber enum #4", input: "enum E {A = x,B,C}", output: `var E;
|
||||
(function (E) {
|
||||
var auto;
|
||||
E[E["A"] = auto = x] = "A";
|
||||
E[E["B"] = ++auto] = "B";
|
||||
E[E["C"] = ++auto] = "C";
|
||||
})(E || (E = {}));`},
|
||||
|
||||
{title: "autonumber enum #5", input: "enum E {A = x,B,C = y}", output: `var E;
|
||||
(function (E) {
|
||||
var auto;
|
||||
E[E["A"] = auto = x] = "A";
|
||||
E[E["B"] = ++auto] = "B";
|
||||
E["C"] = y;
|
||||
if (typeof E.C !== "string") E[E.C] = "C";
|
||||
})(E || (E = {}));`},
|
||||
|
||||
{title: "autonumber enum #6", input: "enum E {A = x,B = y,C = z}", output: `var E;
|
||||
(function (E) {
|
||||
E["A"] = x;
|
||||
if (typeof E.A !== "string") E[E.A] = "A";
|
||||
E["B"] = y;
|
||||
if (typeof E.B !== "string") E[E.B] = "B";
|
||||
E["C"] = z;
|
||||
if (typeof E.C !== "string") E[E.C] = "C";
|
||||
})(E || (E = {}));`},
|
||||
|
||||
{title: "autonumber enum #7", input: "enum E {A = 1,B,C,D='x'}", output: `var E;
|
||||
(function (E) {
|
||||
E[E["A"] = 1] = "A";
|
||||
E[E["B"] = 2] = "B";
|
||||
E[E["C"] = 3] = "C";
|
||||
E["D"] = "x";
|
||||
})(E || (E = {}));`},
|
||||
|
||||
{title: "autonumber enum #8", input: "enum E {A,B=2,C}", output: `var E;
|
||||
(function (E) {
|
||||
E[E["A"] = 0] = "A";
|
||||
E[E["B"] = 2] = "B";
|
||||
E[E["C"] = 3] = "C";
|
||||
})(E || (E = {}));`},
|
||||
|
||||
{title: "autonumber enum #9", input: "enum E {A='x',B=2,C}", output: `var E;
|
||||
(function (E) {
|
||||
E["A"] = "x";
|
||||
E[E["B"] = 2] = "B";
|
||||
E[E["C"] = 3] = "C";
|
||||
})(E || (E = {}));`},
|
||||
|
||||
{title: "autonumber enum #10", input: "enum E {A='x',B=y,C}", output: `var E;
|
||||
(function (E) {
|
||||
var auto;
|
||||
E["A"] = "x";
|
||||
E[E["B"] = auto = y] = "B";
|
||||
E[E["C"] = ++auto] = "C";
|
||||
})(E || (E = {}));`},
|
||||
|
||||
{title: "autonumber enum #11", input: "enum E {A='x',B=1,C,D=y,E,F=3,G}", output: `var E;
|
||||
(function (E) {
|
||||
var auto;
|
||||
E["A"] = "x";
|
||||
E[E["B"] = 1] = "B";
|
||||
E[E["C"] = 2] = "C";
|
||||
E[E["D"] = auto = y] = "D";
|
||||
E[E["E"] = ++auto] = "E";
|
||||
E[E["F"] = 3] = "F";
|
||||
E[E["G"] = 4] = "G";
|
||||
})(E || (E = {}));`},
|
||||
|
||||
{title: "autonumber enum #12", input: "enum E {A=-1,B}", output: `var E;
|
||||
(function (E) {
|
||||
E[E["A"] = -1] = "A";
|
||||
E[E["B"] = 0] = "B";
|
||||
})(E || (E = {}));`},
|
||||
|
||||
{title: "autonumber enum #13", input: "enum E {A='x',B}", output: `var E;
|
||||
(function (E) {
|
||||
E["A"] = "x";
|
||||
E["B"] = void 0;
|
||||
})(E || (E = {}));`},
|
||||
|
||||
{title: "autonumber enum #14", input: "enum E {A,B,C=A|B,D}", output: `var E;
|
||||
(function (E) {
|
||||
E[E["A"] = 0] = "A";
|
||||
E[E["B"] = 1] = "B";
|
||||
E[E["C"] = 1] = "C";
|
||||
E[E["D"] = 2] = "D";
|
||||
})(E || (E = {}));`},
|
||||
|
||||
{title: "string enum #1", input: "enum E {A = 'x',B = 'y',C = 'z'}", output: `var E;
|
||||
(function (E) {
|
||||
E["A"] = "x";
|
||||
E["B"] = "y";
|
||||
E["C"] = "z";
|
||||
})(E || (E = {}));`},
|
||||
|
||||
{title: "string enum #2", input: "enum E {A = 'x',B = 'y',C = `a${A}b${B}c`}", output: `var E;
|
||||
(function (E) {
|
||||
E["A"] = "x";
|
||||
E["B"] = "y";
|
||||
E["C"] = "axbyc";
|
||||
})(E || (E = {}));`},
|
||||
|
||||
{title: "number enum", input: "enum E {A = 0,B = 1,C = 2}", output: `var E;
|
||||
(function (E) {
|
||||
E[E["A"] = 0] = "A";
|
||||
E[E["B"] = 1] = "B";
|
||||
E[E["C"] = 2] = "C";
|
||||
})(E || (E = {}));`},
|
||||
|
||||
{title: "enum self reference #1", input: "enum E {A,B=A}", output: `var E;
|
||||
(function (E) {
|
||||
E[E["A"] = 0] = "A";
|
||||
E[E["B"] = 0] = "B";
|
||||
})(E || (E = {}));`},
|
||||
|
||||
{title: "enum self reference #2", input: "enum E {A=x,B=A}", output: `var E;
|
||||
(function (E) {
|
||||
E["A"] = x;
|
||||
if (typeof E.A !== "string") E[E.A] = "A";
|
||||
E["B"] = E.A;
|
||||
if (typeof E.B !== "string") E[E.B] = "B";
|
||||
})(E || (E = {}));`},
|
||||
|
||||
{title: "enum self reference #3", input: "enum E {'A'=x,B=A}", output: `var E;
|
||||
(function (E) {
|
||||
E["A"] = x;
|
||||
if (typeof E["A"] !== "string") E[E["A"]] = "A";
|
||||
E["B"] = E.A;
|
||||
if (typeof E.B !== "string") E[E.B] = "B";
|
||||
})(E || (E = {}));`},
|
||||
|
||||
{title: "enum self reference #4", input: "enum E {'A'=x,'B '=A}", output: `var E;
|
||||
(function (E) {
|
||||
E["A"] = x;
|
||||
if (typeof E["A"] !== "string") E[E["A"]] = "A";
|
||||
E["B "] = E.A;
|
||||
if (typeof E["B "] !== "string") E[E["B "]] = "B ";
|
||||
})(E || (E = {}));`},
|
||||
|
||||
{title: "enum self reference #5", input: "enum E {A,B=E.A}", output: `var E;
|
||||
(function (E) {
|
||||
E[E["A"] = 0] = "A";
|
||||
E[E["B"] = 0] = "B";
|
||||
})(E || (E = {}));`},
|
||||
|
||||
{title: "export enum", input: "export enum E {A, B}", output: `export { E };
|
||||
var E;
|
||||
(function (E) {
|
||||
E[E["A"] = 0] = "A";
|
||||
E[E["B"] = 1] = "B";
|
||||
})(E || (E = {}));`},
|
||||
|
||||
{title: "const enum", input: "const enum E {A, B}", output: ""},
|
||||
|
||||
{title: "merged enum", input: "enum E {A} enum E {B=A}", output: `var E;
|
||||
(function (E) {
|
||||
E[E["A"] = 0] = "A";
|
||||
})(E || (E = {}));
|
||||
(function (E) {
|
||||
E["B"] = A;
|
||||
if (typeof E.B !== "string") E[E.B] = "B";
|
||||
})(E || (E = {}));`},
|
||||
|
||||
{title: "reverse map enum", input: `enum E {
|
||||
A = 0,
|
||||
B = 1 << 0,
|
||||
C = 1 << 1,
|
||||
D,
|
||||
}`, output: `var E;
|
||||
(function (E) {
|
||||
E[E["A"] = 0] = "A";
|
||||
E[E["B"] = 1] = "B";
|
||||
E[E["C"] = 2] = "C";
|
||||
E[E["D"] = 3] = "D";
|
||||
})(E || (E = {}));`},
|
||||
}
|
||||
|
||||
for _, rec := range data {
|
||||
t.Run(rec.title, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
options := &core.CompilerOptions{}
|
||||
file := parsetestutil.ParseTypeScript(rec.input, false /*jsx*/)
|
||||
parsetestutil.CheckDiagnostics(t, file)
|
||||
binder.BindSourceFile(file)
|
||||
emitContext := printer.NewEmitContext()
|
||||
resolver := binder.NewReferenceResolver(options, binder.ReferenceResolverHooks{})
|
||||
emittestutil.CheckEmit(t, emitContext, tstransforms.NewRuntimeSyntaxTransformer(&transformers.TransformOptions{CompilerOptions: options, Context: emitContext, Resolver: resolver}).TransformSourceFile(file), rec.output)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNamespaceTransformer(t *testing.T) {
|
||||
t.Parallel()
|
||||
data := []struct {
|
||||
title string
|
||||
input string
|
||||
output string
|
||||
}{
|
||||
{title: "empty namespace", input: "namespace N {}", output: ``},
|
||||
|
||||
{title: "export var", input: "namespace N { export var x = 1; }", output: `var N;
|
||||
(function (N) {
|
||||
N.x = 1;
|
||||
})(N || (N = {}));`},
|
||||
|
||||
{title: "export uninitialized var", input: "namespace N { export var x; }", output: `var N;
|
||||
(function (N) {
|
||||
})(N || (N = {}));`},
|
||||
|
||||
{title: "exported var reference", input: "namespace N { export var x = 1; x; }", output: `var N;
|
||||
(function (N) {
|
||||
N.x = 1;
|
||||
N.x;
|
||||
})(N || (N = {}));`},
|
||||
|
||||
{title: "exported var reference across namespaces", input: "namespace N { export var x = 1; } namespace N { x; }", output: `var N;
|
||||
(function (N) {
|
||||
N.x = 1;
|
||||
})(N || (N = {}));
|
||||
(function (N) {
|
||||
x;
|
||||
})(N || (N = {}));`},
|
||||
|
||||
{title: "exported array binding pattern", input: "namespace N { export var [x] = [1]; }", output: `var N;
|
||||
(function (N) {
|
||||
[N.x] = [1];
|
||||
})(N || (N = {}));`},
|
||||
|
||||
{title: "exported array binding pattern + initializer", input: "namespace N { export var [x = 2] = [1]; }", output: `var N;
|
||||
(function (N) {
|
||||
[N.x = 2] = [1];
|
||||
})(N || (N = {}));`},
|
||||
|
||||
{title: "exported array binding pattern + elision", input: "namespace N { export var [, x] = [1]; }", output: `var N;
|
||||
(function (N) {
|
||||
[, N.x] = [1];
|
||||
})(N || (N = {}));`},
|
||||
|
||||
{title: "exported array binding pattern + rest", input: "namespace N { export var [, ...x] = [1]; }", output: `var N;
|
||||
(function (N) {
|
||||
[, ...N.x] = [1];
|
||||
})(N || (N = {}));`},
|
||||
|
||||
{title: "exported array binding pattern + nested array pattern", input: "namespace N { export var [[x]] = [[1]]; }", output: `var N;
|
||||
(function (N) {
|
||||
[[N.x]] = [[1]];
|
||||
})(N || (N = {}));`},
|
||||
|
||||
{title: "exported array binding pattern + nested object pattern", input: "namespace N { export var [{x}] = [{x: 1}]; }", output: `var N;
|
||||
(function (N) {
|
||||
[{ x: N.x }] = [{ x: 1 }];
|
||||
})(N || (N = {}));`},
|
||||
|
||||
{title: "exported object binding pattern", input: "namespace N { export var {x: x} = {x: 1}; }", output: `var N;
|
||||
(function (N) {
|
||||
({ x: N.x } = { x: 1 });
|
||||
})(N || (N = {}));`},
|
||||
|
||||
{title: "exported object binding pattern + shorthand assignment", input: "namespace N { export var {x} = {x: 1}; }", output: `var N;
|
||||
(function (N) {
|
||||
({ x: N.x } = { x: 1 });
|
||||
})(N || (N = {}));`},
|
||||
|
||||
{title: "exported object binding pattern + initializer", input: "namespace N { export var {x: x = 2} = {x: 1}; }", output: `var N;
|
||||
(function (N) {
|
||||
({ x: N.x = 2 } = { x: 1 });
|
||||
})(N || (N = {}));`},
|
||||
|
||||
{title: "exported object binding pattern + shorthand assignment + initializer", input: "namespace N { export var {x = 2} = {x: 1}; }", output: `var N;
|
||||
(function (N) {
|
||||
({ x: N.x = 2 } = { x: 1 });
|
||||
})(N || (N = {}));`},
|
||||
|
||||
{title: "exported object binding pattern + rest", input: "namespace N { export var {...x} = {x: 1}; }", output: `var N;
|
||||
(function (N) {
|
||||
({ ...N.x } = { x: 1 });
|
||||
})(N || (N = {}));`},
|
||||
|
||||
{title: "exported object binding pattern + nested object pattern", input: "namespace N { export var {y:{x}} = {y: {x: 1}}; }", output: `var N;
|
||||
(function (N) {
|
||||
({ y: { x: N.x } } = { y: { x: 1 } });
|
||||
})(N || (N = {}));`},
|
||||
|
||||
{title: "exported object binding pattern + nested array pattern", input: "namespace N { export var {y:[x]} = {y: [1]}; }", output: `var N;
|
||||
(function (N) {
|
||||
({ y: [N.x] } = { y: [1] });
|
||||
})(N || (N = {}));`},
|
||||
|
||||
{title: "export function", input: "namespace N { export function f() {} }", output: `var N;
|
||||
(function (N) {
|
||||
function f() { }
|
||||
N.f = f;
|
||||
})(N || (N = {}));`},
|
||||
|
||||
{title: "export class", input: "namespace N { export class C {} }", output: `var N;
|
||||
(function (N) {
|
||||
class C {
|
||||
}
|
||||
N.C = C;
|
||||
})(N || (N = {}));`},
|
||||
|
||||
{title: "export enum", input: "namespace N { export enum E {A} }", output: `var N;
|
||||
(function (N) {
|
||||
let E;
|
||||
(function (E) {
|
||||
E[E["A"] = 0] = "A";
|
||||
})(E = N.E || (N.E = {}));
|
||||
})(N || (N = {}));`},
|
||||
|
||||
{title: "export namespace", input: "namespace N { export namespace N2 {} }", output: ``},
|
||||
|
||||
{title: "nested namespace", input: "namespace N.N2 { }", output: ``},
|
||||
|
||||
{title: "import=", input: "import X = Y.X;", output: `var X = Y.X;`},
|
||||
|
||||
{title: "export import= at top-level", input: "export import X = Y.X;", output: `export var X = Y.X;`},
|
||||
|
||||
{title: "export import= in namespace", input: "namespace N { export import X = Y.X; }", output: `var N;
|
||||
(function (N) {
|
||||
N.X = Y.X;
|
||||
})(N || (N = {}));`},
|
||||
|
||||
{title: "shorthand property assignment", input: "namespace N { export var x = 1; var y = { x }; }", output: `var N;
|
||||
(function (N) {
|
||||
N.x = 1;
|
||||
var y = { x: N.x };
|
||||
})(N || (N = {}));`},
|
||||
|
||||
{title: "shorthand property assignment pattern", input: "namespace N { export var x; ({x} = {x: 1}); }", output: `var N;
|
||||
(function (N) {
|
||||
({ x: N.x } = { x: 1 });
|
||||
})(N || (N = {}));`},
|
||||
|
||||
{title: "identifier reference in template", input: `namespace N {
|
||||
export var x = 1;
|
||||
` + "`" + `${x}` + "`" + `
|
||||
}`, output: `var N;
|
||||
(function (N) {
|
||||
N.x = 1;
|
||||
` + "`" + `${N.x}` + "`" + `;
|
||||
})(N || (N = {}));`},
|
||||
}
|
||||
|
||||
for _, rec := range data {
|
||||
t.Run(rec.title, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
options := &core.CompilerOptions{}
|
||||
file := parsetestutil.ParseTypeScript(rec.input, false /*jsx*/)
|
||||
parsetestutil.CheckDiagnostics(t, file)
|
||||
binder.BindSourceFile(file)
|
||||
emitContext := printer.NewEmitContext()
|
||||
resolver := binder.NewReferenceResolver(options, binder.ReferenceResolverHooks{})
|
||||
emittestutil.CheckEmit(t, emitContext, tstransforms.NewRuntimeSyntaxTransformer(&transformers.TransformOptions{CompilerOptions: options, Context: emitContext, Resolver: resolver}).TransformSourceFile(file), rec.output)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParameterPropertyTransformer(t *testing.T) {
|
||||
t.Parallel()
|
||||
data := []struct {
|
||||
title string
|
||||
input string
|
||||
output string
|
||||
}{
|
||||
{title: "parameter properties", input: "class C { constructor(public x) { } }", output: `class C {
|
||||
x;
|
||||
constructor(x) {
|
||||
this.x = x;
|
||||
}
|
||||
}`},
|
||||
{title: "parameter properties #2", input: "class C extends B { constructor(public x) { super(); } }", output: `class C extends B {
|
||||
x;
|
||||
constructor(x) {
|
||||
super();
|
||||
this.x = x;
|
||||
}
|
||||
}`},
|
||||
}
|
||||
|
||||
for _, rec := range data {
|
||||
t.Run(rec.title, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
options := &core.CompilerOptions{}
|
||||
file := parsetestutil.ParseTypeScript(rec.input, false /*jsx*/)
|
||||
parsetestutil.CheckDiagnostics(t, file)
|
||||
binder.BindSourceFile(file)
|
||||
emitContext := printer.NewEmitContext()
|
||||
resolver := binder.NewReferenceResolver(options, binder.ReferenceResolverHooks{})
|
||||
opts := &transformers.TransformOptions{Context: emitContext, CompilerOptions: options, Resolver: resolver}
|
||||
file = tstransforms.NewTypeEraserTransformer(opts).TransformSourceFile(file)
|
||||
file = tstransforms.NewRuntimeSyntaxTransformer(opts).TransformSourceFile(file)
|
||||
emittestutil.CheckEmit(t, emitContext, file, rec.output)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1,352 +0,0 @@
|
||||
package tstransforms
|
||||
|
||||
import (
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers"
|
||||
)
|
||||
|
||||
type TypeEraserTransformer struct {
|
||||
transformers.Transformer
|
||||
compilerOptions *core.CompilerOptions
|
||||
parentNode *ast.Node
|
||||
currentNode *ast.Node
|
||||
}
|
||||
|
||||
func NewTypeEraserTransformer(opt *transformers.TransformOptions) *transformers.Transformer {
|
||||
compilerOptions := opt.CompilerOptions
|
||||
emitContext := opt.Context
|
||||
tx := &TypeEraserTransformer{compilerOptions: compilerOptions}
|
||||
return tx.NewTransformer(tx.visit, emitContext)
|
||||
}
|
||||
|
||||
// Pushes a new child node onto the ancestor tracking stack, returning the grandparent node to be restored later via `popNode`.
|
||||
func (tx *TypeEraserTransformer) pushNode(node *ast.Node) (grandparentNode *ast.Node) {
|
||||
grandparentNode = tx.parentNode
|
||||
tx.parentNode = tx.currentNode
|
||||
tx.currentNode = node
|
||||
return grandparentNode
|
||||
}
|
||||
|
||||
// Pops the last child node off the ancestor tracking stack, restoring the grandparent node.
|
||||
func (tx *TypeEraserTransformer) popNode(grandparentNode *ast.Node) {
|
||||
tx.currentNode = tx.parentNode
|
||||
tx.parentNode = grandparentNode
|
||||
}
|
||||
|
||||
func (tx *TypeEraserTransformer) elide(node *ast.Statement) *ast.Statement {
|
||||
return tx.EmitContext().NewNotEmittedStatement(node.AsNode())
|
||||
}
|
||||
|
||||
func (tx *TypeEraserTransformer) visit(node *ast.Node) *ast.Node {
|
||||
if node.SubtreeFacts()&ast.SubtreeContainsTypeScript == 0 {
|
||||
return node
|
||||
}
|
||||
|
||||
if ast.IsStatement(node) && ast.HasSyntacticModifier(node, ast.ModifierFlagsAmbient) {
|
||||
return tx.elide(node)
|
||||
}
|
||||
|
||||
grandparentNode := tx.pushNode(node)
|
||||
defer tx.popNode(grandparentNode)
|
||||
|
||||
switch node.Kind {
|
||||
case
|
||||
// TypeScript accessibility and readonly modifiers are elided
|
||||
ast.KindPublicKeyword,
|
||||
ast.KindPrivateKeyword,
|
||||
ast.KindProtectedKeyword,
|
||||
ast.KindAbstractKeyword,
|
||||
ast.KindOverrideKeyword,
|
||||
ast.KindConstKeyword,
|
||||
ast.KindDeclareKeyword,
|
||||
ast.KindReadonlyKeyword,
|
||||
// TypeScript type nodes are elided.
|
||||
ast.KindArrayType,
|
||||
ast.KindTupleType,
|
||||
ast.KindOptionalType,
|
||||
ast.KindRestType,
|
||||
ast.KindTypeLiteral,
|
||||
ast.KindTypePredicate,
|
||||
ast.KindTypeParameter,
|
||||
ast.KindAnyKeyword,
|
||||
ast.KindUnknownKeyword,
|
||||
ast.KindBooleanKeyword,
|
||||
ast.KindStringKeyword,
|
||||
ast.KindNumberKeyword,
|
||||
ast.KindNeverKeyword,
|
||||
ast.KindVoidKeyword,
|
||||
ast.KindSymbolKeyword,
|
||||
ast.KindConstructorType,
|
||||
ast.KindFunctionType,
|
||||
ast.KindTypeQuery,
|
||||
ast.KindTypeReference,
|
||||
ast.KindUnionType,
|
||||
ast.KindIntersectionType,
|
||||
ast.KindConditionalType,
|
||||
ast.KindParenthesizedType,
|
||||
ast.KindThisType,
|
||||
ast.KindTypeOperator,
|
||||
ast.KindIndexedAccessType,
|
||||
ast.KindMappedType,
|
||||
ast.KindLiteralType,
|
||||
// TypeScript index signatures are elided.
|
||||
ast.KindIndexSignature:
|
||||
return nil
|
||||
|
||||
case ast.KindJSExportAssignment, ast.KindJSImportDeclaration:
|
||||
// reparsed commonjs are elided
|
||||
return nil
|
||||
case ast.KindTypeAliasDeclaration,
|
||||
ast.KindJSTypeAliasDeclaration,
|
||||
ast.KindInterfaceDeclaration:
|
||||
// TypeScript type-only declarations are elided.
|
||||
return tx.elide(node)
|
||||
|
||||
case ast.KindNamespaceExportDeclaration:
|
||||
// TypeScript namespace export declarations are elided.
|
||||
return nil
|
||||
|
||||
case ast.KindModuleDeclaration:
|
||||
if !ast.IsIdentifier(node.Name()) ||
|
||||
!isInstantiatedModule(node, tx.compilerOptions.ShouldPreserveConstEnums()) ||
|
||||
getInnermostModuleDeclarationFromDottedModule(node.AsModuleDeclaration()).Body == nil {
|
||||
// TypeScript module declarations are elided if they are not instantiated or have no body
|
||||
return tx.elide(node)
|
||||
}
|
||||
return tx.Visitor().VisitEachChild(node)
|
||||
|
||||
case ast.KindExpressionWithTypeArguments:
|
||||
n := node.AsExpressionWithTypeArguments()
|
||||
return tx.Factory().UpdateExpressionWithTypeArguments(n, tx.Visitor().VisitNode(n.Expression), nil)
|
||||
|
||||
case ast.KindPropertyDeclaration:
|
||||
if ast.HasSyntacticModifier(node, ast.ModifierFlagsAmbient) {
|
||||
// TypeScript `declare` fields are elided
|
||||
return nil
|
||||
}
|
||||
n := node.AsPropertyDeclaration()
|
||||
return tx.Factory().UpdatePropertyDeclaration(n, tx.Visitor().VisitModifiers(n.Modifiers()), tx.Visitor().VisitNode(n.Name()), nil, nil, tx.Visitor().VisitNode(n.Initializer))
|
||||
|
||||
case ast.KindConstructor:
|
||||
n := node.AsConstructorDeclaration()
|
||||
if n.Body == nil {
|
||||
// TypeScript overloads are elided
|
||||
return nil
|
||||
}
|
||||
return tx.Factory().UpdateConstructorDeclaration(n, nil, nil, tx.Visitor().VisitNodes(n.Parameters), nil, nil, tx.Visitor().VisitNode(n.Body))
|
||||
|
||||
case ast.KindMethodDeclaration:
|
||||
n := node.AsMethodDeclaration()
|
||||
if n.Body == nil {
|
||||
// TypeScript overloads are elided
|
||||
return nil
|
||||
}
|
||||
return tx.Factory().UpdateMethodDeclaration(n, tx.Visitor().VisitModifiers(n.Modifiers()), n.AsteriskToken, tx.Visitor().VisitNode(n.Name()), nil, nil, tx.Visitor().VisitNodes(n.Parameters), nil, nil, tx.Visitor().VisitNode(n.Body))
|
||||
|
||||
case ast.KindGetAccessor:
|
||||
n := node.AsGetAccessorDeclaration()
|
||||
if n.Body == nil {
|
||||
// TypeScript overloads are elided
|
||||
return nil
|
||||
}
|
||||
return tx.Factory().UpdateGetAccessorDeclaration(n, tx.Visitor().VisitModifiers(n.Modifiers()), tx.Visitor().VisitNode(n.Name()), nil, tx.Visitor().VisitNodes(n.Parameters), nil, nil, tx.Visitor().VisitNode(n.Body))
|
||||
|
||||
case ast.KindSetAccessor:
|
||||
n := node.AsSetAccessorDeclaration()
|
||||
if n.Body == nil {
|
||||
// TypeScript overloads are elided
|
||||
return nil
|
||||
}
|
||||
return tx.Factory().UpdateSetAccessorDeclaration(n, tx.Visitor().VisitModifiers(n.Modifiers()), tx.Visitor().VisitNode(n.Name()), nil, tx.Visitor().VisitNodes(n.Parameters), nil, nil, tx.Visitor().VisitNode(n.Body))
|
||||
|
||||
case ast.KindVariableDeclaration:
|
||||
n := node.AsVariableDeclaration()
|
||||
return tx.Factory().UpdateVariableDeclaration(n, tx.Visitor().VisitNode(n.Name()), nil, nil, tx.Visitor().VisitNode(n.Initializer))
|
||||
|
||||
case ast.KindHeritageClause:
|
||||
n := node.AsHeritageClause()
|
||||
if n.Token == ast.KindImplementsKeyword {
|
||||
// TypeScript `implements` clauses are elided
|
||||
return nil
|
||||
}
|
||||
return tx.Factory().UpdateHeritageClause(n, tx.Visitor().VisitNodes(n.Types))
|
||||
|
||||
case ast.KindClassDeclaration:
|
||||
n := node.AsClassDeclaration()
|
||||
return tx.Factory().UpdateClassDeclaration(n, tx.Visitor().VisitModifiers(n.Modifiers()), tx.Visitor().VisitNode(n.Name()), nil, tx.Visitor().VisitNodes(n.HeritageClauses), tx.Visitor().VisitNodes(n.Members))
|
||||
|
||||
case ast.KindClassExpression:
|
||||
n := node.AsClassExpression()
|
||||
return tx.Factory().UpdateClassExpression(n, tx.Visitor().VisitModifiers(n.Modifiers()), tx.Visitor().VisitNode(n.Name()), nil, tx.Visitor().VisitNodes(n.HeritageClauses), tx.Visitor().VisitNodes(n.Members))
|
||||
|
||||
case ast.KindFunctionDeclaration:
|
||||
n := node.AsFunctionDeclaration()
|
||||
if n.Body == nil {
|
||||
// TypeScript overloads are elided
|
||||
return tx.elide(node)
|
||||
}
|
||||
return tx.Factory().UpdateFunctionDeclaration(n, tx.Visitor().VisitModifiers(n.Modifiers()), n.AsteriskToken, tx.Visitor().VisitNode(n.Name()), nil, tx.Visitor().VisitNodes(n.Parameters), nil, nil, tx.Visitor().VisitNode(n.Body))
|
||||
|
||||
case ast.KindFunctionExpression:
|
||||
n := node.AsFunctionExpression()
|
||||
return tx.Factory().UpdateFunctionExpression(n, tx.Visitor().VisitModifiers(n.Modifiers()), n.AsteriskToken, tx.Visitor().VisitNode(n.Name()), nil, tx.Visitor().VisitNodes(n.Parameters), nil, nil, tx.Visitor().VisitNode(n.Body))
|
||||
|
||||
case ast.KindArrowFunction:
|
||||
n := node.AsArrowFunction()
|
||||
return tx.Factory().UpdateArrowFunction(n, tx.Visitor().VisitModifiers(n.Modifiers()), nil, tx.Visitor().VisitNodes(n.Parameters), nil, nil, n.EqualsGreaterThanToken, tx.Visitor().VisitNode(n.Body))
|
||||
|
||||
case ast.KindParameter:
|
||||
if ast.IsThisParameter(node) {
|
||||
// TypeScript `this` parameters are elided
|
||||
return nil
|
||||
}
|
||||
n := node.AsParameterDeclaration()
|
||||
// preserve parameter property modifiers to be handled by the runtime transformer
|
||||
var modifiers *ast.ModifierList
|
||||
if ast.IsParameterPropertyDeclaration(node, tx.parentNode) {
|
||||
modifiers = transformers.ExtractModifiers(tx.EmitContext(), n.Modifiers(), ast.ModifierFlagsParameterPropertyModifier)
|
||||
}
|
||||
return tx.Factory().UpdateParameterDeclaration(n, modifiers, n.DotDotDotToken, tx.Visitor().VisitNode(n.Name()), nil, nil, tx.Visitor().VisitNode(n.Initializer))
|
||||
|
||||
case ast.KindCallExpression:
|
||||
n := node.AsCallExpression()
|
||||
return tx.Factory().UpdateCallExpression(n, tx.Visitor().VisitNode(n.Expression), n.QuestionDotToken, nil, tx.Visitor().VisitNodes(n.Arguments))
|
||||
|
||||
case ast.KindNewExpression:
|
||||
n := node.AsNewExpression()
|
||||
return tx.Factory().UpdateNewExpression(n, tx.Visitor().VisitNode(n.Expression), nil, tx.Visitor().VisitNodes(n.Arguments))
|
||||
|
||||
case ast.KindTaggedTemplateExpression:
|
||||
n := node.AsTaggedTemplateExpression()
|
||||
return tx.Factory().UpdateTaggedTemplateExpression(n, tx.Visitor().VisitNode(n.Tag), n.QuestionDotToken, nil, tx.Visitor().VisitNode(n.Template))
|
||||
|
||||
case ast.KindNonNullExpression, ast.KindTypeAssertionExpression, ast.KindAsExpression, ast.KindSatisfiesExpression:
|
||||
partial := tx.Factory().NewPartiallyEmittedExpression(tx.Visitor().VisitNode(node.Expression()))
|
||||
tx.EmitContext().SetOriginal(partial, node)
|
||||
partial.Loc = node.Loc
|
||||
return partial
|
||||
|
||||
case ast.KindParenthesizedExpression:
|
||||
n := node.AsParenthesizedExpression()
|
||||
expression := ast.SkipOuterExpressions(n.Expression, ^(ast.OEKAssertions | ast.OEKExpressionsWithTypeArguments))
|
||||
if ast.IsAssertionExpression(expression) || ast.IsSatisfiesExpression(expression) {
|
||||
partial := tx.Factory().NewPartiallyEmittedExpression(tx.Visitor().VisitNode(n.Expression))
|
||||
tx.EmitContext().SetOriginal(partial, node)
|
||||
partial.Loc = node.Loc
|
||||
return partial
|
||||
}
|
||||
return tx.Visitor().VisitEachChild(node)
|
||||
|
||||
case ast.KindJsxSelfClosingElement:
|
||||
n := node.AsJsxSelfClosingElement()
|
||||
return tx.Factory().UpdateJsxSelfClosingElement(n, tx.Visitor().VisitNode(n.TagName), nil, tx.Visitor().VisitNode(n.Attributes))
|
||||
|
||||
case ast.KindJsxOpeningElement:
|
||||
n := node.AsJsxOpeningElement()
|
||||
return tx.Factory().UpdateJsxOpeningElement(n, tx.Visitor().VisitNode(n.TagName), nil, tx.Visitor().VisitNode(n.Attributes))
|
||||
|
||||
case ast.KindImportEqualsDeclaration:
|
||||
n := node.AsImportEqualsDeclaration()
|
||||
if n.IsTypeOnly {
|
||||
// elide type-only imports
|
||||
return nil
|
||||
}
|
||||
return tx.Visitor().VisitEachChild(node)
|
||||
|
||||
case ast.KindImportDeclaration:
|
||||
n := node.AsImportDeclaration()
|
||||
if n.ImportClause == nil {
|
||||
// Do not elide a side-effect only import declaration.
|
||||
// import "foo";
|
||||
return node
|
||||
}
|
||||
importClause := tx.Visitor().VisitNode(n.ImportClause)
|
||||
if importClause == nil {
|
||||
return nil
|
||||
}
|
||||
return tx.Factory().UpdateImportDeclaration(n, n.Modifiers(), importClause, n.ModuleSpecifier, n.Attributes)
|
||||
|
||||
case ast.KindImportClause:
|
||||
n := node.AsImportClause()
|
||||
if n.IsTypeOnly() {
|
||||
// Always elide type-only imports
|
||||
return nil
|
||||
}
|
||||
name := n.Name()
|
||||
namedBindings := tx.Visitor().VisitNode(n.NamedBindings)
|
||||
if name == nil && namedBindings == nil {
|
||||
// all import bindings were elided
|
||||
return nil
|
||||
}
|
||||
return tx.Factory().UpdateImportClause(n, n.PhaseModifier, name, namedBindings)
|
||||
|
||||
case ast.KindNamedImports:
|
||||
n := node.AsNamedImports()
|
||||
if len(n.Elements.Nodes) == 0 {
|
||||
// Do not elide a side-effect only import declaration.
|
||||
return node
|
||||
}
|
||||
elements := tx.Visitor().VisitNodes(n.Elements)
|
||||
if !tx.compilerOptions.VerbatimModuleSyntax.IsTrue() && len(elements.Nodes) == 0 {
|
||||
// all import specifiers were elided
|
||||
return nil
|
||||
}
|
||||
return tx.Factory().UpdateNamedImports(n, elements)
|
||||
|
||||
case ast.KindImportSpecifier:
|
||||
n := node.AsImportSpecifier()
|
||||
if n.IsTypeOnly {
|
||||
// elide type-only or unused imports
|
||||
return nil
|
||||
}
|
||||
return node
|
||||
|
||||
case ast.KindExportDeclaration:
|
||||
n := node.AsExportDeclaration()
|
||||
if n.IsTypeOnly {
|
||||
// elide type-only exports
|
||||
return nil
|
||||
}
|
||||
var exportClause *ast.Node
|
||||
if n.ExportClause != nil {
|
||||
exportClause = tx.Visitor().VisitNode(n.ExportClause)
|
||||
if exportClause == nil {
|
||||
// all export bindings were elided
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return tx.Factory().UpdateExportDeclaration(n, nil /*modifiers*/, false /*isTypeOnly*/, exportClause, tx.Visitor().VisitNode(n.ModuleSpecifier), tx.Visitor().VisitNode(n.Attributes))
|
||||
|
||||
case ast.KindNamedExports:
|
||||
n := node.AsNamedExports()
|
||||
if len(n.Elements.Nodes) == 0 {
|
||||
// Do not elide an empty export declaration.
|
||||
return node
|
||||
}
|
||||
|
||||
elements := tx.Visitor().VisitNodes(n.Elements)
|
||||
if !tx.compilerOptions.VerbatimModuleSyntax.IsTrue() && len(elements.Nodes) == 0 {
|
||||
// all export specifiers were elided
|
||||
return nil
|
||||
}
|
||||
return tx.Factory().UpdateNamedExports(n, elements)
|
||||
|
||||
case ast.KindExportSpecifier:
|
||||
n := node.AsExportSpecifier()
|
||||
if n.IsTypeOnly {
|
||||
// elide unused export
|
||||
return nil
|
||||
}
|
||||
return node
|
||||
|
||||
case ast.KindEnumDeclaration:
|
||||
if ast.IsEnumConst(node) {
|
||||
return node
|
||||
}
|
||||
return tx.Visitor().VisitEachChild(node)
|
||||
|
||||
default:
|
||||
return tx.Visitor().VisitEachChild(node)
|
||||
}
|
||||
}
|
||||
@ -1,106 +0,0 @@
|
||||
package tstransforms_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/testutil/emittestutil"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/testutil/parsetestutil"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers/tstransforms"
|
||||
)
|
||||
|
||||
func TestTypeEraser(t *testing.T) {
|
||||
t.Parallel()
|
||||
data := []struct {
|
||||
title string
|
||||
input string
|
||||
output string
|
||||
jsx bool
|
||||
vms bool
|
||||
}{
|
||||
{title: "Modifiers", input: "class C { public x; private y }", output: "class C {\n x;\n y;\n}"},
|
||||
{title: "InterfaceDeclaration", input: "interface I { }", output: ""},
|
||||
{title: "TypeAliasDeclaration", input: "type T = U;", output: ""},
|
||||
{title: "NamespaceExportDeclaration", input: "export as namespace N;", output: ""},
|
||||
{title: "UninstantiatedNamespace1", input: "namespace N {}", output: ""},
|
||||
{title: "UninstantiatedNamespace2", input: "namespace N { export interface I {} }", output: ""},
|
||||
{title: "UninstantiatedNamespace3", input: "namespace N { export type T = U; }", output: ""},
|
||||
{title: "ExpressionWithTypeArguments", input: "F<T>", output: "F;"},
|
||||
{title: "PropertyDeclaration1", input: "class C { declare x; }", output: "class C {\n}"},
|
||||
{title: "PropertyDeclaration2", input: "class C { public x: number; }", output: "class C {\n x;\n}"},
|
||||
{title: "PropertyDeclaration3", input: "class C { public static x: number; }", output: "class C {\n static x;\n}"},
|
||||
{title: "ConstructorDeclaration1", input: "class C { constructor(); }", output: "class C {\n}"},
|
||||
{title: "ConstructorDeclaration2", input: "class C { public constructor() {} }", output: "class C {\n constructor() { }\n}"},
|
||||
{title: "MethodDeclaration1", input: "class C { m(); }", output: "class C {\n}"},
|
||||
{title: "MethodDeclaration2", input: "class C { public m<T>(): U {} }", output: "class C {\n m() { }\n}"},
|
||||
{title: "MethodDeclaration3", input: "class C { public static m<T>(): U {} }", output: "class C {\n static m() { }\n}"},
|
||||
{title: "GetAccessorDeclaration1", input: "class C { get m(); }", output: "class C {\n}"},
|
||||
{title: "GetAccessorDeclaration2", input: "class C { public get m<T>(): U {} }", output: "class C {\n get m() { }\n}"},
|
||||
{title: "GetAccessorDeclaration3", input: "class C { public static get m<T>(): U {} }", output: "class C {\n static get m() { }\n}"},
|
||||
{title: "SetAccessorDeclaration1", input: "class C { set m(v); }", output: "class C {\n}"},
|
||||
{title: "SetAccessorDeclaration2", input: "class C { public set m<T>(v): U {} }", output: "class C {\n set m(v) { }\n}"},
|
||||
{title: "SetAccessorDeclaration3", input: "class C { public static set m<T>(v): U {} }", output: "class C {\n static set m(v) { }\n}"},
|
||||
{title: "IndexSignature", input: "class C { [key: string]: number; }", output: "class C {\n}"},
|
||||
{title: "VariableDeclaration1", input: "declare var a;", output: ""},
|
||||
{title: "VariableDeclaration2", input: "var a: number", output: "var a;"},
|
||||
{title: "HeritageClause", input: "class C implements I {}", output: "class C {\n}"},
|
||||
{title: "ClassDeclaration1", input: "declare class C {}", output: ""},
|
||||
{title: "ClassDeclaration2", input: "class C<T> {}", output: "class C {\n}"},
|
||||
{title: "ClassExpression", input: "(class C<T> {})", output: "(class C {\n});"},
|
||||
{title: "FunctionDeclaration1", input: "declare function f() {}", output: ""},
|
||||
{title: "FunctionDeclaration2", input: "function f();", output: ""},
|
||||
{title: "FunctionDeclaration3", input: "function f<T>(): U {}", output: "function f() { }"},
|
||||
{title: "FunctionExpression", input: "(function f<T>(): U {})", output: "(function f() { });"},
|
||||
{title: "ArrowFunction", input: "(<T>(): U => {})", output: "(() => { });"},
|
||||
{title: "ParameterDeclaration", input: "function f(this: x, a: number, b?: boolean) {}", output: "function f(a, b) { }"},
|
||||
{title: "CallExpression", input: "f<T>()", output: "f();"},
|
||||
{title: "NewExpression1", input: "new f<T>()", output: "new f();"},
|
||||
{title: "NewExpression2", input: "new f<T>", output: "new f;"},
|
||||
{title: "TaggedTemplateExpression", input: "f<T>``", output: "f ``;"},
|
||||
{title: "NonNullExpression", input: "x!", output: "x;"},
|
||||
{title: "TypeAssertionExpression#1", input: "<T>x", output: "x;"},
|
||||
{title: "TypeAssertionExpression#2", input: "(<T>x).c", output: "x.c;"},
|
||||
{title: "AsExpression#1", input: "x as T", output: "x;"},
|
||||
{title: "AsExpression#2", input: "(x as T).c", output: "x.c;"},
|
||||
{title: "SatisfiesExpression#1", input: "x satisfies T", output: "x;"},
|
||||
{title: "SatisfiesExpression#2", input: "(x satisfies T).c", output: "x.c;"},
|
||||
{title: "JsxSelfClosingElement", input: "<x<T> />", output: "<x />;", jsx: true},
|
||||
{title: "JsxOpeningElement", input: "<x<T>></x>", output: "<x></x>;", jsx: true},
|
||||
{title: "ImportEqualsDeclaration#1", input: "import x = require(\"m\");", output: "import x = require(\"m\");"},
|
||||
{title: "ImportEqualsDeclaration#2", input: "import type x = require(\"m\");", output: ""},
|
||||
{title: "ImportEqualsDeclaration#3", input: "import x = y;", output: "import x = y;"},
|
||||
{title: "ImportEqualsDeclaration#4", input: "import type x = y;", output: ""},
|
||||
{title: "ImportDeclaration#1", input: "import \"m\";", output: "import \"m\";"},
|
||||
{title: "ImportDeclaration#2", input: "import * as x from \"m\"; x;", output: "import * as x from \"m\";\nx;"},
|
||||
{title: "ImportDeclaration#3", input: "import x from \"m\"; x;", output: "import x from \"m\";\nx;"},
|
||||
{title: "ImportDeclaration#4", input: "import { x } from \"m\"; x;", output: "import { x } from \"m\";\nx;"},
|
||||
{title: "ImportDeclaration#5", input: "import type * as x from \"m\";", output: ""},
|
||||
{title: "ImportDeclaration#6", input: "import type x from \"m\";", output: ""},
|
||||
{title: "ImportDeclaration#7", input: "import type { x } from \"m\";", output: ""},
|
||||
{title: "ImportDeclaration#8", input: "import { type x } from \"m\";", output: ""},
|
||||
{title: "ImportDeclaration#9", input: "import { type x } from \"m\";", output: "import {} from \"m\";", vms: true},
|
||||
{title: "ExportDeclaration#1", input: "export * from \"m\";", output: "export * from \"m\";"},
|
||||
{title: "ExportDeclaration#2", input: "export * as x from \"m\";", output: "export * as x from \"m\";"},
|
||||
{title: "ExportDeclaration#3", input: "export { x } from \"m\";", output: "export { x } from \"m\";"},
|
||||
{title: "ExportDeclaration#4", input: "export type * from \"m\";", output: ""},
|
||||
{title: "ExportDeclaration#5", input: "export type * as x from \"m\";", output: ""},
|
||||
{title: "ExportDeclaration#6", input: "export type { x } from \"m\";", output: ""},
|
||||
{title: "ExportDeclaration#7", input: "export { type x } from \"m\";", output: ""},
|
||||
{title: "ExportDeclaration#7", input: "export { type x } from \"m\";", output: "export {} from \"m\";", vms: true},
|
||||
}
|
||||
|
||||
for _, rec := range data {
|
||||
t.Run(rec.title, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
file := parsetestutil.ParseTypeScript(rec.input, rec.jsx)
|
||||
parsetestutil.CheckDiagnostics(t, file)
|
||||
compilerOptions := &core.CompilerOptions{}
|
||||
if rec.vms {
|
||||
compilerOptions.VerbatimModuleSyntax = core.TSTrue
|
||||
}
|
||||
emittestutil.CheckEmit(t, nil, tstransforms.NewTypeEraserTransformer(&transformers.TransformOptions{CompilerOptions: compilerOptions, Context: printer.NewEmitContext()}).TransformSourceFile(file), rec.output)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1,41 +0,0 @@
|
||||
package tstransforms
|
||||
|
||||
import (
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/jsnum"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
|
||||
)
|
||||
|
||||
func convertEntityNameToExpression(emitContext *printer.EmitContext, name *ast.EntityName) *ast.Expression {
|
||||
if ast.IsQualifiedName(name) {
|
||||
left := convertEntityNameToExpression(emitContext, name.AsQualifiedName().Left)
|
||||
right := name.AsQualifiedName().Right
|
||||
prop := emitContext.Factory.NewPropertyAccessExpression(left, nil /*questionDotToken*/, right, ast.NodeFlagsNone)
|
||||
emitContext.SetOriginal(prop, name)
|
||||
emitContext.AssignCommentAndSourceMapRanges(prop, name)
|
||||
return prop
|
||||
}
|
||||
return name.Clone(emitContext.Factory)
|
||||
}
|
||||
|
||||
func constantExpression(value any, factory *printer.NodeFactory) *ast.Expression {
|
||||
switch value := value.(type) {
|
||||
case string:
|
||||
return factory.NewStringLiteral(value)
|
||||
case jsnum.Number:
|
||||
if value.IsInf() || value.IsNaN() {
|
||||
return nil
|
||||
}
|
||||
if value < 0 {
|
||||
return factory.NewPrefixUnaryExpression(ast.KindMinusToken, constantExpression(-value, factory))
|
||||
}
|
||||
return factory.NewNumericLiteral(value.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isInstantiatedModule(node *ast.ModuleDeclarationNode, preserveConstEnums bool) bool {
|
||||
moduleState := ast.GetModuleInstanceState(node)
|
||||
return moduleState == ast.ModuleInstanceStateInstantiated ||
|
||||
(preserveConstEnums && moduleState == ast.ModuleInstanceStateConstEnumOnly)
|
||||
}
|
||||
@ -1,274 +0,0 @@
|
||||
package transformers
|
||||
|
||||
import (
|
||||
"slices"
|
||||
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/scanner"
|
||||
)
|
||||
|
||||
func IsGeneratedIdentifier(emitContext *printer.EmitContext, name *ast.IdentifierNode) bool {
|
||||
return emitContext.HasAutoGenerateInfo(name)
|
||||
}
|
||||
|
||||
func IsHelperName(emitContext *printer.EmitContext, name *ast.IdentifierNode) bool {
|
||||
return emitContext.EmitFlags(name)&printer.EFHelperName != 0
|
||||
}
|
||||
|
||||
func IsLocalName(emitContext *printer.EmitContext, name *ast.IdentifierNode) bool {
|
||||
return emitContext.EmitFlags(name)&printer.EFLocalName != 0
|
||||
}
|
||||
|
||||
func IsExportName(emitContext *printer.EmitContext, name *ast.IdentifierNode) bool {
|
||||
return emitContext.EmitFlags(name)&printer.EFExportName != 0
|
||||
}
|
||||
|
||||
func IsIdentifierReference(name *ast.IdentifierNode, parent *ast.Node) bool {
|
||||
switch parent.Kind {
|
||||
case ast.KindBinaryExpression,
|
||||
ast.KindPrefixUnaryExpression,
|
||||
ast.KindPostfixUnaryExpression,
|
||||
ast.KindYieldExpression,
|
||||
ast.KindAsExpression,
|
||||
ast.KindSatisfiesExpression,
|
||||
ast.KindElementAccessExpression,
|
||||
ast.KindNonNullExpression,
|
||||
ast.KindSpreadElement,
|
||||
ast.KindSpreadAssignment,
|
||||
ast.KindParenthesizedExpression,
|
||||
ast.KindArrayLiteralExpression,
|
||||
ast.KindDeleteExpression,
|
||||
ast.KindTypeOfExpression,
|
||||
ast.KindVoidExpression,
|
||||
ast.KindAwaitExpression,
|
||||
ast.KindTypeAssertionExpression,
|
||||
ast.KindExpressionWithTypeArguments,
|
||||
ast.KindJsxSelfClosingElement,
|
||||
ast.KindJsxSpreadAttribute,
|
||||
ast.KindJsxExpression,
|
||||
ast.KindCommaListExpression,
|
||||
ast.KindPartiallyEmittedExpression:
|
||||
// all immediate children that can be `Identifier` would be instances of `IdentifierReference`
|
||||
return true
|
||||
case ast.KindComputedPropertyName,
|
||||
ast.KindDecorator,
|
||||
ast.KindIfStatement,
|
||||
ast.KindDoStatement,
|
||||
ast.KindWhileStatement,
|
||||
ast.KindWithStatement,
|
||||
ast.KindReturnStatement,
|
||||
ast.KindSwitchStatement,
|
||||
ast.KindCaseClause,
|
||||
ast.KindThrowStatement,
|
||||
ast.KindExpressionStatement,
|
||||
ast.KindExportAssignment,
|
||||
ast.KindJSExportAssignment,
|
||||
ast.KindPropertyAccessExpression,
|
||||
ast.KindTemplateSpan:
|
||||
// only an `Expression()` child that can be `Identifier` would be an instance of `IdentifierReference`
|
||||
return parent.Expression() == name
|
||||
case ast.KindVariableDeclaration,
|
||||
ast.KindParameter,
|
||||
ast.KindBindingElement,
|
||||
ast.KindPropertyDeclaration,
|
||||
ast.KindPropertySignature,
|
||||
ast.KindPropertyAssignment,
|
||||
ast.KindEnumMember,
|
||||
ast.KindJsxAttribute:
|
||||
// only an `Initializer()` child that can be `Identifier` would be an instance of `IdentifierReference`
|
||||
return parent.Initializer() == name
|
||||
case ast.KindForStatement:
|
||||
return parent.AsForStatement().Initializer == name ||
|
||||
parent.AsForStatement().Condition == name ||
|
||||
parent.AsForStatement().Incrementor == name
|
||||
case ast.KindForInStatement,
|
||||
ast.KindForOfStatement:
|
||||
return parent.AsForInOrOfStatement().Initializer == name ||
|
||||
parent.AsForInOrOfStatement().Expression == name
|
||||
case ast.KindImportEqualsDeclaration:
|
||||
return parent.AsImportEqualsDeclaration().ModuleReference == name
|
||||
case ast.KindArrowFunction:
|
||||
return parent.AsArrowFunction().Body == name
|
||||
case ast.KindConditionalExpression:
|
||||
return parent.AsConditionalExpression().Condition == name ||
|
||||
parent.AsConditionalExpression().WhenTrue == name ||
|
||||
parent.AsConditionalExpression().WhenFalse == name
|
||||
case ast.KindCallExpression:
|
||||
return parent.AsCallExpression().Expression == name ||
|
||||
slices.Contains(parent.AsCallExpression().Arguments.Nodes, name)
|
||||
case ast.KindNewExpression:
|
||||
return parent.AsNewExpression().Expression == name ||
|
||||
parent.AsNewExpression().Arguments.Nodes != nil &&
|
||||
slices.Contains(parent.AsNewExpression().Arguments.Nodes, name)
|
||||
case ast.KindTaggedTemplateExpression:
|
||||
return parent.AsTaggedTemplateExpression().Tag == name
|
||||
case ast.KindImportAttribute:
|
||||
return parent.AsImportAttribute().Value == name
|
||||
case ast.KindJsxOpeningElement:
|
||||
return parent.AsJsxOpeningElement().TagName == name
|
||||
case ast.KindJsxClosingElement:
|
||||
return parent.AsJsxClosingElement().TagName == name
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func convertBindingElementToArrayAssignmentElement(emitContext *printer.EmitContext, element *ast.BindingElement) *ast.Expression {
|
||||
if element.Name() == nil {
|
||||
elision := emitContext.Factory.NewOmittedExpression()
|
||||
emitContext.SetOriginal(elision, element.AsNode())
|
||||
emitContext.AssignCommentAndSourceMapRanges(elision, element.AsNode())
|
||||
return elision
|
||||
}
|
||||
if element.DotDotDotToken != nil {
|
||||
spread := emitContext.Factory.NewSpreadElement(element.Name())
|
||||
emitContext.SetOriginal(spread, element.AsNode())
|
||||
emitContext.AssignCommentAndSourceMapRanges(spread, element.AsNode())
|
||||
return spread
|
||||
}
|
||||
expression := convertBindingNameToAssignmentElementTarget(emitContext, element.Name())
|
||||
if element.Initializer != nil {
|
||||
assignment := emitContext.Factory.NewAssignmentExpression(expression, element.Initializer)
|
||||
emitContext.SetOriginal(assignment, element.AsNode())
|
||||
emitContext.AssignCommentAndSourceMapRanges(assignment, element.AsNode())
|
||||
return assignment
|
||||
}
|
||||
return expression
|
||||
}
|
||||
|
||||
func convertBindingElementToObjectAssignmentElement(emitContext *printer.EmitContext, element *ast.BindingElement) *ast.ObjectLiteralElement {
|
||||
if element.DotDotDotToken != nil {
|
||||
spread := emitContext.Factory.NewSpreadAssignment(element.Name())
|
||||
emitContext.SetOriginal(spread, element.AsNode())
|
||||
emitContext.AssignCommentAndSourceMapRanges(spread, element.AsNode())
|
||||
return spread
|
||||
}
|
||||
if element.PropertyName != nil {
|
||||
expression := convertBindingNameToAssignmentElementTarget(emitContext, element.Name())
|
||||
if element.Initializer != nil {
|
||||
expression = emitContext.Factory.NewAssignmentExpression(expression, element.Initializer)
|
||||
}
|
||||
assignment := emitContext.Factory.NewPropertyAssignment(nil /*modifiers*/, element.PropertyName, nil /*postfixToken*/, nil /*typeNode*/, expression)
|
||||
emitContext.SetOriginal(assignment, element.AsNode())
|
||||
emitContext.AssignCommentAndSourceMapRanges(assignment, element.AsNode())
|
||||
return assignment
|
||||
}
|
||||
var equalsToken *ast.TokenNode
|
||||
if element.Initializer != nil {
|
||||
equalsToken = emitContext.Factory.NewToken(ast.KindEqualsToken)
|
||||
}
|
||||
assignment := emitContext.Factory.NewShorthandPropertyAssignment(
|
||||
nil, /*modifiers*/
|
||||
element.Name(),
|
||||
nil, /*postfixToken*/
|
||||
nil, /*typeNode*/
|
||||
equalsToken,
|
||||
element.Initializer,
|
||||
)
|
||||
emitContext.SetOriginal(assignment, element.AsNode())
|
||||
emitContext.AssignCommentAndSourceMapRanges(assignment, element.AsNode())
|
||||
return assignment
|
||||
}
|
||||
|
||||
func ConvertBindingPatternToAssignmentPattern(emitContext *printer.EmitContext, element *ast.BindingPattern) *ast.Expression {
|
||||
switch element.Kind {
|
||||
case ast.KindArrayBindingPattern:
|
||||
return convertBindingElementToArrayAssignmentPattern(emitContext, element)
|
||||
case ast.KindObjectBindingPattern:
|
||||
return convertBindingElementToObjectAssignmentPattern(emitContext, element)
|
||||
default:
|
||||
panic("Unknown binding pattern")
|
||||
}
|
||||
}
|
||||
|
||||
func convertBindingElementToObjectAssignmentPattern(emitContext *printer.EmitContext, element *ast.BindingPattern) *ast.Expression {
|
||||
var properties []*ast.ObjectLiteralElement
|
||||
for _, element := range element.Elements.Nodes {
|
||||
properties = append(properties, convertBindingElementToObjectAssignmentElement(emitContext, element.AsBindingElement()))
|
||||
}
|
||||
propertyList := emitContext.Factory.NewNodeList(properties)
|
||||
propertyList.Loc = element.Elements.Loc
|
||||
object := emitContext.Factory.NewObjectLiteralExpression(propertyList, false /*multiLine*/)
|
||||
emitContext.SetOriginal(object, element.AsNode())
|
||||
emitContext.AssignCommentAndSourceMapRanges(object, element.AsNode())
|
||||
return object
|
||||
}
|
||||
|
||||
func convertBindingElementToArrayAssignmentPattern(emitContext *printer.EmitContext, element *ast.BindingPattern) *ast.Expression {
|
||||
var elements []*ast.Expression
|
||||
for _, element := range element.Elements.Nodes {
|
||||
elements = append(elements, convertBindingElementToArrayAssignmentElement(emitContext, element.AsBindingElement()))
|
||||
}
|
||||
elementList := emitContext.Factory.NewNodeList(elements)
|
||||
elementList.Loc = element.Elements.Loc
|
||||
object := emitContext.Factory.NewArrayLiteralExpression(elementList, false /*multiLine*/)
|
||||
emitContext.SetOriginal(object, element.AsNode())
|
||||
emitContext.AssignCommentAndSourceMapRanges(object, element.AsNode())
|
||||
return object
|
||||
}
|
||||
|
||||
func convertBindingNameToAssignmentElementTarget(emitContext *printer.EmitContext, element *ast.Node) *ast.Expression {
|
||||
if ast.IsBindingPattern(element) {
|
||||
return ConvertBindingPatternToAssignmentPattern(emitContext, element.AsBindingPattern())
|
||||
}
|
||||
return element
|
||||
}
|
||||
|
||||
func ConvertVariableDeclarationToAssignmentExpression(emitContext *printer.EmitContext, element *ast.VariableDeclaration) *ast.Expression {
|
||||
if element.Initializer == nil {
|
||||
return nil
|
||||
}
|
||||
expression := convertBindingNameToAssignmentElementTarget(emitContext, element.Name())
|
||||
assignment := emitContext.Factory.NewAssignmentExpression(expression, element.Initializer)
|
||||
emitContext.SetOriginal(assignment, element.AsNode())
|
||||
emitContext.AssignCommentAndSourceMapRanges(assignment, element.AsNode())
|
||||
return assignment
|
||||
}
|
||||
|
||||
func SingleOrMany(nodes []*ast.Node, factory *printer.NodeFactory) *ast.Node {
|
||||
if len(nodes) == 1 {
|
||||
return nodes[0]
|
||||
}
|
||||
return factory.NewSyntaxList(nodes)
|
||||
}
|
||||
|
||||
// Used in the module transformer to check if an expression is reasonably without sideeffect,
|
||||
//
|
||||
// and thus better to copy into multiple places rather than to cache in a temporary variable
|
||||
// - this is mostly subjective beyond the requirement that the expression not be sideeffecting
|
||||
//
|
||||
// Also used by the logical assignment downleveling transform to skip temp variables when they're
|
||||
// not needed.
|
||||
func IsSimpleCopiableExpression(expression *ast.Expression) bool {
|
||||
return ast.IsStringLiteralLike(expression) ||
|
||||
ast.IsNumericLiteral(expression) ||
|
||||
ast.IsKeywordKind(expression.Kind) ||
|
||||
ast.IsIdentifier(expression)
|
||||
}
|
||||
|
||||
func IsOriginalNodeSingleLine(emitContext *printer.EmitContext, node *ast.Node) bool {
|
||||
if node == nil {
|
||||
return false
|
||||
}
|
||||
original := emitContext.MostOriginal(node)
|
||||
if original == nil {
|
||||
return false
|
||||
}
|
||||
source := ast.GetSourceFileOfNode(original)
|
||||
if source == nil {
|
||||
return false
|
||||
}
|
||||
startLine, _ := scanner.GetECMALineAndCharacterOfPosition(source, original.Loc.Pos())
|
||||
endLine, _ := scanner.GetECMALineAndCharacterOfPosition(source, original.Loc.End())
|
||||
return startLine == endLine
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple inlinable expression is an expression which can be copied into multiple locations
|
||||
* without risk of repeating any sideeffects and whose value could not possibly change between
|
||||
* any such locations
|
||||
*/
|
||||
func IsSimpleInlineableExpression(expression *ast.Expression) bool {
|
||||
return !ast.IsIdentifier(expression) && IsSimpleCopiableExpression(expression)
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user