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