1981 lines
74 KiB
Go
1981 lines
74 KiB
Go
package declarations
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/collections"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/debug"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/diagnostics"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/jsnum"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/modulespecifiers"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/nodebuilder"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/scanner"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
|
|
)
|
|
|
|
type ReferencedFilePair struct {
|
|
file *ast.SourceFile
|
|
ref *ast.FileReference
|
|
}
|
|
|
|
type OutputPaths interface {
|
|
DeclarationFilePath() string
|
|
JsFilePath() string
|
|
}
|
|
|
|
// Used to be passed in the TransformationContext, which is now just an EmitContext
|
|
type DeclarationEmitHost interface {
|
|
modulespecifiers.ModuleSpecifierGenerationHost
|
|
GetCurrentDirectory() string
|
|
UseCaseSensitiveFileNames() bool
|
|
GetSourceFileFromReference(origin *ast.SourceFile, ref *ast.FileReference) *ast.SourceFile
|
|
|
|
GetOutputPathsFor(file *ast.SourceFile, forceDtsPaths bool) OutputPaths
|
|
GetResolutionModeOverride(node *ast.Node) core.ResolutionMode
|
|
GetEffectiveDeclarationFlags(node *ast.Node, flags ast.ModifierFlags) ast.ModifierFlags
|
|
GetEmitResolver() printer.EmitResolver
|
|
}
|
|
|
|
type DeclarationTransformer struct {
|
|
transformers.Transformer
|
|
host DeclarationEmitHost
|
|
compilerOptions *core.CompilerOptions
|
|
tracker *SymbolTrackerImpl
|
|
state *SymbolTrackerSharedState
|
|
resolver printer.EmitResolver
|
|
declarationFilePath string
|
|
declarationMapPath string
|
|
|
|
isBundledEmit bool
|
|
needsDeclare bool
|
|
needsScopeFixMarker bool
|
|
resultHasScopeMarker bool
|
|
enclosingDeclaration *ast.Node
|
|
resultHasExternalModuleIndicator bool
|
|
suppressNewDiagnosticContexts bool
|
|
lateStatementReplacementMap map[ast.NodeId]*ast.Node
|
|
expandoHosts collections.Set[ast.NodeId]
|
|
rawReferencedFiles []ReferencedFilePair
|
|
rawTypeReferenceDirectives []*ast.FileReference
|
|
rawLibReferenceDirectives []*ast.FileReference
|
|
}
|
|
|
|
// TODO: Convert to transformers.TransformerFactory signature to allow more automatic composition with other transforms
|
|
func NewDeclarationTransformer(host DeclarationEmitHost, context *printer.EmitContext, compilerOptions *core.CompilerOptions, declarationFilePath string, declarationMapPath string) *DeclarationTransformer {
|
|
resolver := host.GetEmitResolver()
|
|
state := &SymbolTrackerSharedState{isolatedDeclarations: compilerOptions.IsolatedDeclarations.IsTrue(), resolver: resolver}
|
|
tracker := NewSymbolTracker(host, resolver, state)
|
|
// TODO: Use new host GetOutputPathsFor method instead of passing in entrypoint paths (which will also better support bundled emit)
|
|
tx := &DeclarationTransformer{
|
|
host: host,
|
|
compilerOptions: compilerOptions,
|
|
tracker: tracker,
|
|
state: state,
|
|
resolver: resolver,
|
|
declarationFilePath: declarationFilePath,
|
|
declarationMapPath: declarationMapPath,
|
|
}
|
|
tx.NewTransformer(tx.visit, context)
|
|
return tx
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) GetDiagnostics() []*ast.Diagnostic {
|
|
return tx.state.diagnostics
|
|
}
|
|
|
|
const declarationEmitNodeBuilderFlags = nodebuilder.FlagsMultilineObjectLiterals |
|
|
nodebuilder.FlagsWriteClassExpressionAsTypeLiteral |
|
|
nodebuilder.FlagsUseTypeOfFunction |
|
|
nodebuilder.FlagsUseStructuralFallback |
|
|
nodebuilder.FlagsAllowEmptyTuple |
|
|
nodebuilder.FlagsGenerateNamesForShadowedTypeParams |
|
|
nodebuilder.FlagsNoTruncation
|
|
|
|
const declarationEmitInternalNodeBuilderFlags = nodebuilder.InternalFlagsAllowUnresolvedNames
|
|
|
|
// functions as both `visitDeclarationStatements` and `transformRoot`, utilitzing SyntaxList nodes
|
|
func (tx *DeclarationTransformer) visit(node *ast.Node) *ast.Node {
|
|
if node == nil {
|
|
return nil
|
|
}
|
|
// !!! TODO: Bundle support?
|
|
switch node.Kind {
|
|
case ast.KindSourceFile:
|
|
return tx.visitSourceFile(node.AsSourceFile())
|
|
// statements we keep but do something to
|
|
case ast.KindFunctionDeclaration,
|
|
ast.KindModuleDeclaration,
|
|
ast.KindImportEqualsDeclaration,
|
|
ast.KindInterfaceDeclaration,
|
|
ast.KindClassDeclaration,
|
|
ast.KindJSTypeAliasDeclaration,
|
|
ast.KindTypeAliasDeclaration,
|
|
ast.KindEnumDeclaration,
|
|
ast.KindVariableStatement,
|
|
ast.KindImportDeclaration,
|
|
ast.KindJSImportDeclaration,
|
|
ast.KindExportDeclaration,
|
|
ast.KindJSExportAssignment,
|
|
ast.KindExportAssignment:
|
|
return tx.visitDeclarationStatements(node)
|
|
// statements we elide
|
|
case ast.KindBreakStatement,
|
|
ast.KindContinueStatement,
|
|
ast.KindDebuggerStatement,
|
|
ast.KindDoStatement,
|
|
ast.KindEmptyStatement,
|
|
ast.KindForInStatement,
|
|
ast.KindForOfStatement,
|
|
ast.KindForStatement,
|
|
ast.KindIfStatement,
|
|
ast.KindLabeledStatement,
|
|
ast.KindReturnStatement,
|
|
ast.KindSwitchStatement,
|
|
ast.KindThrowStatement,
|
|
ast.KindTryStatement,
|
|
ast.KindWhileStatement,
|
|
ast.KindWithStatement,
|
|
ast.KindNotEmittedStatement,
|
|
ast.KindBlock,
|
|
ast.KindMissingDeclaration:
|
|
return nil
|
|
case ast.KindExpressionStatement:
|
|
return tx.visitExpressionStatement(node.AsExpressionStatement())
|
|
// parts of things, things we just visit children of
|
|
default:
|
|
return tx.visitDeclarationSubtree(node)
|
|
}
|
|
}
|
|
|
|
func throwDiagnostic(result printer.SymbolAccessibilityResult) *SymbolAccessibilityDiagnostic {
|
|
panic("Diagnostic emitted without context")
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) visitSourceFile(node *ast.SourceFile) *ast.Node {
|
|
if node.IsDeclarationFile {
|
|
return node.AsNode()
|
|
}
|
|
|
|
tx.isBundledEmit = false
|
|
tx.needsDeclare = true
|
|
tx.needsScopeFixMarker = false
|
|
tx.resultHasScopeMarker = false
|
|
tx.enclosingDeclaration = node.AsNode()
|
|
tx.state.getSymbolAccessibilityDiagnostic = throwDiagnostic
|
|
tx.resultHasExternalModuleIndicator = false
|
|
tx.suppressNewDiagnosticContexts = false
|
|
tx.state.lateMarkedStatements = make([]*ast.Node, 0)
|
|
tx.lateStatementReplacementMap = make(map[ast.NodeId]*ast.Node)
|
|
tx.expandoHosts = collections.Set[ast.NodeId]{}
|
|
tx.rawReferencedFiles = make([]ReferencedFilePair, 0)
|
|
tx.rawTypeReferenceDirectives = make([]*ast.FileReference, 0)
|
|
tx.rawLibReferenceDirectives = make([]*ast.FileReference, 0)
|
|
tx.state.currentSourceFile = node
|
|
tx.collectFileReferences(node)
|
|
tx.resolver.PrecalculateDeclarationEmitVisibility(node)
|
|
updated := tx.transformSourceFile(node)
|
|
tx.state.currentSourceFile = nil
|
|
return updated
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) collectFileReferences(sourceFile *ast.SourceFile) {
|
|
tx.rawReferencedFiles = append(tx.rawReferencedFiles, core.Map(sourceFile.ReferencedFiles, func(ref *ast.FileReference) ReferencedFilePair { return ReferencedFilePair{file: sourceFile, ref: ref} })...)
|
|
tx.rawTypeReferenceDirectives = append(tx.rawTypeReferenceDirectives, sourceFile.TypeReferenceDirectives...)
|
|
tx.rawLibReferenceDirectives = append(tx.rawLibReferenceDirectives, sourceFile.LibReferenceDirectives...)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformSourceFile(node *ast.SourceFile) *ast.Node {
|
|
var combinedStatements *ast.StatementList
|
|
statements := tx.Visitor().VisitNodes(node.Statements)
|
|
combinedStatements = tx.transformAndReplaceLatePaintedStatements(statements)
|
|
combinedStatements.Loc = statements.Loc // setTextRange
|
|
if ast.IsExternalOrCommonJSModule(node) && (!tx.resultHasExternalModuleIndicator || (tx.needsScopeFixMarker && !tx.resultHasScopeMarker)) {
|
|
marker := createEmptyExports(tx.Factory().AsNodeFactory())
|
|
newList := append(combinedStatements.Nodes, marker)
|
|
withMarker := tx.Factory().NewNodeList(newList)
|
|
withMarker.Loc = combinedStatements.Loc
|
|
combinedStatements = withMarker
|
|
}
|
|
outputFilePath := tspath.GetDirectoryPath(tspath.NormalizeSlashes(tx.declarationFilePath))
|
|
result := tx.Factory().UpdateSourceFile(node, combinedStatements, node.EndOfFileToken)
|
|
result.AsSourceFile().LibReferenceDirectives = tx.getLibReferences()
|
|
result.AsSourceFile().TypeReferenceDirectives = tx.getTypeReferences()
|
|
result.AsSourceFile().IsDeclarationFile = true
|
|
result.AsSourceFile().ReferencedFiles = tx.getReferencedFiles(outputFilePath)
|
|
return result.AsNode()
|
|
}
|
|
|
|
func createEmptyExports(factory *ast.NodeFactory) *ast.Node {
|
|
return factory.NewExportDeclaration(nil /*isTypeOnly*/, false, factory.NewNamedExports(factory.NewNodeList([]*ast.Node{})), nil, nil)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformAndReplaceLatePaintedStatements(statements *ast.StatementList) *ast.StatementList {
|
|
// This is a `while` loop because `handleSymbolAccessibilityError` can see additional import aliases marked as visible during
|
|
// error handling which must now be included in the output and themselves checked for errors.
|
|
// For example:
|
|
// ```
|
|
// module A {
|
|
// export module Q {}
|
|
// import B = Q;
|
|
// import C = B;
|
|
// export import D = C;
|
|
// }
|
|
// ```
|
|
// In such a scenario, only Q and D are initially visible, but we don't consider imports as private names - instead we say they if they are referenced they must
|
|
// be recorded. So while checking D's visibility we mark C as visible, then we must check C which in turn marks B, completing the chain of
|
|
// dependent imports and allowing a valid declaration file output. Today, this dependent alias marking only happens for internal import aliases.
|
|
for true {
|
|
if len(tx.state.lateMarkedStatements) == 0 {
|
|
break
|
|
}
|
|
|
|
next := tx.state.lateMarkedStatements[0]
|
|
tx.state.lateMarkedStatements = tx.state.lateMarkedStatements[1:]
|
|
|
|
saveNeedsDeclare := tx.needsDeclare
|
|
tx.needsDeclare = next.Parent != nil && ast.IsSourceFile(next.Parent) && !(ast.IsExternalModule(next.Parent.AsSourceFile()) && tx.isBundledEmit)
|
|
|
|
result := tx.transformTopLevelDeclaration(next)
|
|
|
|
tx.needsDeclare = saveNeedsDeclare
|
|
original := tx.EmitContext().MostOriginal(next)
|
|
id := ast.GetNodeId(original)
|
|
tx.lateStatementReplacementMap[id] = result
|
|
}
|
|
|
|
// And lastly, we need to get the final form of all those indetermine import declarations from before and add them to the output list
|
|
// (and remove them from the set to examine for outter declarations)
|
|
results := make([]*ast.Node, 0, len(statements.Nodes))
|
|
for _, statement := range statements.Nodes {
|
|
if !ast.IsLateVisibilityPaintedStatement(statement) {
|
|
results = append(results, statement)
|
|
continue
|
|
}
|
|
original := tx.EmitContext().MostOriginal(statement)
|
|
id := ast.GetNodeId(original)
|
|
replacement, ok := tx.lateStatementReplacementMap[id]
|
|
if !ok {
|
|
results = append(results, statement)
|
|
continue // not replaced
|
|
}
|
|
if replacement == nil {
|
|
continue // deleted
|
|
}
|
|
if replacement.Kind == ast.KindSyntaxList {
|
|
if !tx.needsScopeFixMarker || !tx.resultHasExternalModuleIndicator {
|
|
for _, elem := range replacement.AsSyntaxList().Children {
|
|
if needsScopeMarker(elem) {
|
|
tx.needsScopeFixMarker = true
|
|
}
|
|
if ast.IsSourceFile(statement.Parent) && ast.IsExternalModuleIndicator(replacement) {
|
|
tx.resultHasExternalModuleIndicator = true
|
|
}
|
|
}
|
|
}
|
|
results = append(results, replacement.AsSyntaxList().Children...)
|
|
} else {
|
|
if needsScopeMarker(replacement) {
|
|
tx.needsScopeFixMarker = true
|
|
}
|
|
if ast.IsSourceFile(statement.Parent) && ast.IsExternalModuleIndicator(replacement) {
|
|
tx.resultHasExternalModuleIndicator = true
|
|
}
|
|
results = append(results, replacement)
|
|
}
|
|
}
|
|
|
|
return tx.Factory().NewNodeList(results)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) getReferencedFiles(outputFilePath string) (results []*ast.FileReference) {
|
|
// Handle path rewrites for triple slash ref comments
|
|
for _, pair := range tx.rawReferencedFiles {
|
|
sourceFile := pair.file
|
|
ref := pair.ref
|
|
|
|
if !ref.Preserve {
|
|
continue
|
|
}
|
|
|
|
file := tx.host.GetSourceFileFromReference(sourceFile, ref)
|
|
if file == nil {
|
|
continue
|
|
}
|
|
|
|
var declFileName string
|
|
if file.IsDeclarationFile {
|
|
declFileName = file.FileName()
|
|
} else {
|
|
// !!! bundled emit support, omit bundled refs
|
|
// if (tx.isBundledEmit && contains((node as Bundle).sourceFiles, file)) continue
|
|
paths := tx.host.GetOutputPathsFor(file, true)
|
|
// Try to use output path for referenced file, or output js path if that doesn't exist, or the input path if all else fails
|
|
declFileName = paths.DeclarationFilePath()
|
|
if len(declFileName) == 0 {
|
|
declFileName = paths.JsFilePath()
|
|
}
|
|
if len(declFileName) == 0 {
|
|
declFileName = file.FileName()
|
|
}
|
|
}
|
|
// Should only be missing if the source file is missing a fileName (at which point we can't name a reference to it anyway)
|
|
// TODO: Shouldn't this be a crash or assert instead of a silent continue?
|
|
if len(declFileName) == 0 {
|
|
continue
|
|
}
|
|
|
|
fileName := tspath.GetRelativePathToDirectoryOrUrl(
|
|
outputFilePath,
|
|
declFileName,
|
|
false, // TODO: Probably unsafe to assume this isn't a URL, but that's what strada does
|
|
tspath.ComparePathsOptions{
|
|
CurrentDirectory: tx.host.GetCurrentDirectory(),
|
|
UseCaseSensitiveFileNames: tx.host.UseCaseSensitiveFileNames(),
|
|
},
|
|
)
|
|
|
|
results = append(results, &ast.FileReference{
|
|
TextRange: core.NewTextRange(-1, -1),
|
|
FileName: fileName,
|
|
ResolutionMode: ref.ResolutionMode,
|
|
Preserve: ref.Preserve,
|
|
})
|
|
}
|
|
return results
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) getLibReferences() (result []*ast.FileReference) {
|
|
// clone retained references
|
|
for _, ref := range tx.rawLibReferenceDirectives {
|
|
if !ref.Preserve {
|
|
continue
|
|
}
|
|
result = append(result, &ast.FileReference{
|
|
TextRange: core.NewTextRange(-1, -1),
|
|
FileName: ref.FileName,
|
|
ResolutionMode: ref.ResolutionMode,
|
|
Preserve: ref.Preserve,
|
|
})
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) getTypeReferences() (result []*ast.FileReference) {
|
|
// clone retained references
|
|
for _, ref := range tx.rawTypeReferenceDirectives {
|
|
if !ref.Preserve {
|
|
continue
|
|
}
|
|
result = append(result, &ast.FileReference{
|
|
TextRange: core.NewTextRange(-1, -1),
|
|
FileName: ref.FileName,
|
|
ResolutionMode: ref.ResolutionMode,
|
|
Preserve: ref.Preserve,
|
|
})
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) visitDeclarationSubtree(input *ast.Node) *ast.Node {
|
|
// !!! TODO: stripInternal support?
|
|
// if (shouldStripInternal(input)) return nil
|
|
if ast.IsDeclaration(input) {
|
|
if isDeclarationAndNotVisible(tx.EmitContext(), tx.resolver, input) {
|
|
return nil
|
|
}
|
|
if ast.HasDynamicName(input) {
|
|
if tx.state.isolatedDeclarations {
|
|
// Classes and object literals usually elide properties with computed names that are not of a literal type
|
|
// In isolated declarations TSC needs to error on these as we don't know the type in a DTE.
|
|
if !tx.resolver.IsDefinitelyReferenceToGlobalSymbolObject(input.Name().Expression()) {
|
|
if ast.IsClassDeclaration(input.Parent) || ast.IsObjectLiteralExpression(input.Parent) {
|
|
// !!! TODO: isolatedDeclarations diagnostics
|
|
// context.addDiagnostic(createDiagnosticForNode(input, diagnostics.Computed_property_names_on_class_or_object_literals_cannot_be_inferred_with_isolatedDeclarations))
|
|
return nil
|
|
} else if (ast.IsInterfaceDeclaration(input.Parent) || ast.IsTypeLiteralNode(input.Parent)) && !ast.IsEntityNameExpression(input.Name().Expression()) {
|
|
// Type declarations just need to double-check that the input computed name is an entity name expression
|
|
// !!! TODO: isolatedDeclarations diagnostics
|
|
// context.addDiagnostic(createDiagnosticForNode(input, diagnostics.Computed_properties_must_be_number_or_string_literals_variables_or_dotted_expressions_with_isolatedDeclarations))
|
|
return nil
|
|
}
|
|
}
|
|
} else if !tx.resolver.IsLateBound(tx.EmitContext().ParseNode(input)) || !ast.IsEntityNameExpression(input.Name().AsComputedPropertyName().Expression) {
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
|
|
// Elide implementation signatures from overload sets
|
|
if ast.IsFunctionLike(input) && tx.resolver.IsImplementationOfOverload(input) {
|
|
return nil
|
|
}
|
|
|
|
if input.Kind == ast.KindSemicolonClassElement {
|
|
return nil
|
|
}
|
|
|
|
previousEnclosingDeclaration := tx.enclosingDeclaration
|
|
if isEnclosingDeclaration(input) {
|
|
tx.enclosingDeclaration = input
|
|
}
|
|
|
|
canProdiceDiagnostic := canProduceDiagnostics(input)
|
|
oldWithinObjectLiteralType := tx.suppressNewDiagnosticContexts
|
|
shouldEnterSuppressNewDiagnosticsContextContext := (input.Kind == ast.KindTypeLiteral || input.Kind == ast.KindMappedType) && !(input.Parent.Kind == ast.KindTypeAliasDeclaration || input.Parent.Kind == ast.KindJSTypeAliasDeclaration)
|
|
|
|
oldDiag := tx.state.getSymbolAccessibilityDiagnostic
|
|
if canProdiceDiagnostic && !tx.suppressNewDiagnosticContexts {
|
|
tx.state.getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(input)
|
|
}
|
|
oldName := tx.state.errorNameNode
|
|
|
|
if shouldEnterSuppressNewDiagnosticsContextContext {
|
|
tx.suppressNewDiagnosticContexts = true
|
|
}
|
|
|
|
var result *ast.Node
|
|
|
|
switch input.Kind {
|
|
case ast.KindMappedType:
|
|
result = tx.transformMappedTypeNode(input.AsMappedTypeNode())
|
|
case ast.KindHeritageClause:
|
|
result = tx.transformHeritageClause(input.AsHeritageClause())
|
|
case ast.KindMethodSignature:
|
|
result = tx.transformMethodSignatureDeclaration(input.AsMethodSignatureDeclaration())
|
|
case ast.KindMethodDeclaration:
|
|
result = tx.transformMethodDeclaration(input.AsMethodDeclaration())
|
|
case ast.KindConstructSignature:
|
|
result = tx.transformConstructSignatureDeclaration(input.AsConstructSignatureDeclaration())
|
|
case ast.KindConstructor:
|
|
result = tx.transformConstructorDeclaration(input.AsConstructorDeclaration())
|
|
case ast.KindGetAccessor:
|
|
result = tx.transformGetAccesorDeclaration(input.AsGetAccessorDeclaration())
|
|
case ast.KindSetAccessor:
|
|
result = tx.transformSetAccessorDeclaration(input.AsSetAccessorDeclaration())
|
|
case ast.KindPropertyDeclaration:
|
|
result = tx.transformPropertyDeclaration(input.AsPropertyDeclaration())
|
|
case ast.KindPropertySignature:
|
|
result = tx.transformPropertySignatureDeclaration(input.AsPropertySignatureDeclaration())
|
|
case ast.KindCallSignature:
|
|
result = tx.transformCallSignatureDeclaration(input.AsCallSignatureDeclaration())
|
|
case ast.KindIndexSignature:
|
|
result = tx.transformIndexSignatureDeclaration(input.AsIndexSignatureDeclaration())
|
|
case ast.KindVariableDeclaration:
|
|
result = tx.transformVariableDeclaration(input.AsVariableDeclaration())
|
|
case ast.KindTypeParameter:
|
|
result = tx.transformTypeParameterDeclaration(input.AsTypeParameter())
|
|
case ast.KindExpressionWithTypeArguments:
|
|
result = tx.transformExpressionWithTypeArguments(input.AsExpressionWithTypeArguments())
|
|
case ast.KindTypeReference:
|
|
result = tx.transformTypeReference(input.AsTypeReference())
|
|
case ast.KindConditionalType:
|
|
result = tx.transformConditionalTypeNode(input.AsConditionalTypeNode())
|
|
case ast.KindFunctionType:
|
|
result = tx.transformFunctionTypeNode(input.AsFunctionTypeNode())
|
|
case ast.KindConstructorType:
|
|
result = tx.transformConstructorTypeNode(input.AsConstructorTypeNode())
|
|
case ast.KindImportType:
|
|
result = tx.transformImportTypeNode(input.AsImportTypeNode())
|
|
case ast.KindTypeQuery:
|
|
tx.checkEntityNameVisibility(input.AsTypeQueryNode().ExprName, tx.enclosingDeclaration)
|
|
result = tx.Visitor().VisitEachChild(input)
|
|
case ast.KindTupleType:
|
|
result = tx.Visitor().VisitEachChild(input)
|
|
if result != nil {
|
|
if transformers.IsOriginalNodeSingleLine(tx.EmitContext(), input) {
|
|
tx.EmitContext().AddEmitFlags(result, printer.EFSingleLine)
|
|
}
|
|
}
|
|
case ast.KindJSDocTypeExpression:
|
|
result = tx.transformJSDocTypeExpression(input.AsJSDocTypeExpression())
|
|
case ast.KindJSDocTypeLiteral:
|
|
result = tx.transformJSDocTypeLiteral(input.AsJSDocTypeLiteral())
|
|
case ast.KindJSDocPropertyTag:
|
|
result = tx.transformJSDocPropertyTag(input.AsJSDocParameterOrPropertyTag())
|
|
case ast.KindJSDocAllType:
|
|
result = tx.transformJSDocAllType(input.AsJSDocAllType())
|
|
case ast.KindJSDocNullableType:
|
|
result = tx.transformJSDocNullableType(input.AsJSDocNullableType())
|
|
case ast.KindJSDocNonNullableType:
|
|
result = tx.transformJSDocNonNullableType(input.AsJSDocNonNullableType())
|
|
case ast.KindJSDocOptionalType:
|
|
result = tx.transformJSDocOptionalType(input.AsJSDocOptionalType())
|
|
case ast.KindJSDocVariadicType:
|
|
result = tx.transformJSDocVariadicType(input.AsJSDocVariadicType())
|
|
default:
|
|
result = tx.Visitor().VisitEachChild(input)
|
|
}
|
|
|
|
if result != nil && canProdiceDiagnostic && ast.HasDynamicName(input) {
|
|
tx.checkName(input)
|
|
}
|
|
|
|
tx.enclosingDeclaration = previousEnclosingDeclaration
|
|
tx.state.getSymbolAccessibilityDiagnostic = oldDiag
|
|
tx.state.errorNameNode = oldName
|
|
tx.suppressNewDiagnosticContexts = oldWithinObjectLiteralType
|
|
return result
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) checkName(node *ast.Node) {
|
|
oldDiag := tx.state.getSymbolAccessibilityDiagnostic
|
|
if !tx.suppressNewDiagnosticContexts {
|
|
tx.state.getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNodeName(node)
|
|
}
|
|
tx.state.errorNameNode = node.Name()
|
|
debug.Assert(ast.HasDynamicName(node)) // Should only be called with dynamic names
|
|
entityName := node.Name().AsComputedPropertyName().Expression
|
|
tx.checkEntityNameVisibility(entityName, tx.enclosingDeclaration)
|
|
if !tx.suppressNewDiagnosticContexts {
|
|
tx.state.getSymbolAccessibilityDiagnostic = oldDiag
|
|
}
|
|
tx.state.errorNameNode = nil
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformMappedTypeNode(input *ast.MappedTypeNode) *ast.Node {
|
|
// handle missing template type nodes, since the printer does not
|
|
var typeNode *ast.Node
|
|
if input.Type == nil {
|
|
typeNode = tx.Factory().NewKeywordTypeNode(ast.KindAnyKeyword)
|
|
} else {
|
|
typeNode = tx.Visitor().Visit(input.Type)
|
|
}
|
|
return tx.Factory().UpdateMappedTypeNode(
|
|
input,
|
|
input.ReadonlyToken,
|
|
tx.Visitor().Visit(input.TypeParameter),
|
|
tx.Visitor().Visit(input.NameType),
|
|
input.QuestionToken,
|
|
typeNode,
|
|
nil,
|
|
)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformHeritageClause(clause *ast.HeritageClause) *ast.Node {
|
|
retainedClauses := core.Filter(clause.Types.Nodes, func(t *ast.Node) bool {
|
|
return ast.IsEntityNameExpression(t.AsExpressionWithTypeArguments().Expression) ||
|
|
(clause.Token == ast.KindExtendsKeyword && t.Expression().Kind == ast.KindNullKeyword)
|
|
})
|
|
if len(retainedClauses) == 0 {
|
|
return nil // elide empty clause
|
|
}
|
|
if len(retainedClauses) == len(clause.Types.Nodes) {
|
|
return tx.Visitor().VisitEachChild(clause.AsNode())
|
|
}
|
|
return tx.Factory().UpdateHeritageClause(
|
|
clause,
|
|
tx.Visitor().VisitNodes(tx.Factory().NewNodeList(retainedClauses)),
|
|
)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformImportTypeNode(input *ast.ImportTypeNode) *ast.Node {
|
|
if !ast.IsLiteralImportTypeNode(input.AsNode()) {
|
|
return input.AsNode()
|
|
}
|
|
return tx.Factory().UpdateImportTypeNode(
|
|
input,
|
|
input.IsTypeOf,
|
|
tx.Factory().UpdateLiteralTypeNode(
|
|
input.Argument.AsLiteralTypeNode(),
|
|
tx.rewriteModuleSpecifier(input.AsNode(), input.Argument.AsLiteralTypeNode().Literal),
|
|
),
|
|
input.Attributes,
|
|
input.Qualifier,
|
|
tx.Visitor().VisitNodes(input.TypeArguments),
|
|
)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformConstructorTypeNode(input *ast.ConstructorTypeNode) *ast.Node {
|
|
return tx.Factory().UpdateConstructorTypeNode(
|
|
input,
|
|
tx.ensureModifiers(input.AsNode()),
|
|
tx.Visitor().VisitNodes(input.TypeParameters),
|
|
tx.updateParamList(input.AsNode(), input.Parameters),
|
|
tx.Visitor().Visit(input.Type),
|
|
)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformFunctionTypeNode(input *ast.FunctionTypeNode) *ast.Node {
|
|
return tx.Factory().UpdateFunctionTypeNode(
|
|
input,
|
|
tx.Visitor().VisitNodes(input.TypeParameters),
|
|
tx.updateParamList(input.AsNode(), input.Parameters),
|
|
tx.Visitor().Visit(input.Type),
|
|
)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformConditionalTypeNode(input *ast.ConditionalTypeNode) *ast.Node {
|
|
checkType := tx.Visitor().Visit(input.CheckType)
|
|
extendsType := tx.Visitor().Visit(input.ExtendsType)
|
|
oldEnclosingDecl := tx.enclosingDeclaration
|
|
tx.enclosingDeclaration = input.TrueType
|
|
trueType := tx.Visitor().Visit(input.TrueType)
|
|
tx.enclosingDeclaration = oldEnclosingDecl
|
|
falseType := tx.Visitor().Visit(input.FalseType)
|
|
|
|
return tx.Factory().UpdateConditionalTypeNode(
|
|
input,
|
|
checkType,
|
|
extendsType,
|
|
trueType,
|
|
falseType,
|
|
)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformTypeReference(input *ast.TypeReferenceNode) *ast.Node {
|
|
tx.checkEntityNameVisibility(input.TypeName, tx.enclosingDeclaration)
|
|
return tx.Visitor().VisitEachChild(input.AsNode())
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformExpressionWithTypeArguments(input *ast.ExpressionWithTypeArguments) *ast.Node {
|
|
if ast.IsEntityName(input.Expression) || ast.IsEntityNameExpression(input.Expression) {
|
|
tx.checkEntityNameVisibility(input.Expression, tx.enclosingDeclaration)
|
|
}
|
|
return tx.Visitor().VisitEachChild(input.AsNode())
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformTypeParameterDeclaration(input *ast.TypeParameterDeclaration) *ast.Node {
|
|
if isPrivateMethodTypeParameter(tx.host, input) && (input.DefaultType != nil || input.Constraint != nil) {
|
|
return tx.Factory().UpdateTypeParameterDeclaration(
|
|
input,
|
|
input.Modifiers(),
|
|
input.Name(),
|
|
nil,
|
|
nil,
|
|
)
|
|
}
|
|
return tx.Visitor().VisitEachChild(input.AsNode())
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformVariableDeclaration(input *ast.VariableDeclaration) *ast.Node {
|
|
if ast.IsBindingPattern(input.Name()) {
|
|
return tx.recreateBindingPattern(input.Name().AsBindingPattern())
|
|
}
|
|
// Variable declaration types also suppress new diagnostic contexts, provided the contexts wouldn't be made for binding pattern types
|
|
tx.suppressNewDiagnosticContexts = true
|
|
return tx.Factory().UpdateVariableDeclaration(
|
|
input,
|
|
input.Name(),
|
|
nil,
|
|
tx.ensureType(input.AsNode(), false),
|
|
tx.ensureNoInitializer(input.AsNode()),
|
|
)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) recreateBindingPattern(input *ast.BindingPattern) *ast.Node {
|
|
var results []*ast.Node
|
|
for _, elem := range input.Elements.Nodes {
|
|
result := tx.recreateBindingElement(elem.AsBindingElement())
|
|
if result == nil {
|
|
continue
|
|
}
|
|
if result.Kind == ast.KindSyntaxList {
|
|
results = append(results, result.AsSyntaxList().Children...)
|
|
} else {
|
|
results = append(results, result)
|
|
}
|
|
}
|
|
if len(results) == 0 {
|
|
return nil
|
|
}
|
|
if len(results) == 1 {
|
|
return results[0]
|
|
}
|
|
return tx.Factory().NewSyntaxList(results)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) recreateBindingElement(e *ast.BindingElement) *ast.Node {
|
|
if e.Name() == nil {
|
|
return nil
|
|
}
|
|
if !getBindingNameVisible(tx.resolver, e.AsNode()) {
|
|
return nil
|
|
}
|
|
if ast.IsBindingPattern(e.Name()) {
|
|
return tx.recreateBindingPattern(e.Name().AsBindingPattern())
|
|
}
|
|
return tx.Factory().NewVariableDeclaration(
|
|
e.Name(),
|
|
nil,
|
|
tx.ensureType(e.AsNode(), false),
|
|
nil, // TODO: possible strada bug - not emitting const initialized binding pattern elements?
|
|
)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformIndexSignatureDeclaration(input *ast.IndexSignatureDeclaration) *ast.Node {
|
|
t := tx.Visitor().Visit(input.Type)
|
|
if t == nil {
|
|
t = tx.Factory().NewKeywordTypeNode(ast.KindAnyKeyword)
|
|
}
|
|
return tx.Factory().UpdateIndexSignatureDeclaration(
|
|
input,
|
|
tx.ensureModifiers(input.AsNode()),
|
|
tx.updateParamList(input.AsNode(), input.Parameters),
|
|
t,
|
|
)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformCallSignatureDeclaration(input *ast.CallSignatureDeclaration) *ast.Node {
|
|
return tx.Factory().UpdateCallSignatureDeclaration(
|
|
input,
|
|
tx.ensureTypeParams(input.AsNode(), input.TypeParameters),
|
|
tx.updateParamList(input.AsNode(), input.Parameters),
|
|
tx.ensureType(input.AsNode(), false),
|
|
)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformPropertySignatureDeclaration(input *ast.PropertySignatureDeclaration) *ast.Node {
|
|
if ast.IsPrivateIdentifier(input.Name()) {
|
|
return nil
|
|
}
|
|
return tx.Factory().UpdatePropertySignatureDeclaration(
|
|
input,
|
|
tx.ensureModifiers(input.AsNode()),
|
|
input.Name(),
|
|
input.PostfixToken,
|
|
tx.ensureType(input.AsNode(), false),
|
|
tx.ensureNoInitializer(input.AsNode()), // TODO: possible strada bug (fixed here) - const property signatures never initialized
|
|
)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformPropertyDeclaration(input *ast.PropertyDeclaration) *ast.Node {
|
|
if ast.IsPrivateIdentifier(input.Name()) {
|
|
return nil
|
|
}
|
|
// Remove definite assignment assertion (!) from declaration files
|
|
postfixToken := input.PostfixToken
|
|
if postfixToken != nil && postfixToken.Kind == ast.KindExclamationToken {
|
|
postfixToken = nil
|
|
}
|
|
return tx.Factory().UpdatePropertyDeclaration(
|
|
input,
|
|
tx.ensureModifiers(input.AsNode()),
|
|
input.Name(),
|
|
postfixToken,
|
|
tx.ensureType(input.AsNode(), false),
|
|
tx.ensureNoInitializer(input.AsNode()),
|
|
)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformSetAccessorDeclaration(input *ast.SetAccessorDeclaration) *ast.Node {
|
|
if ast.IsPrivateIdentifier(input.Name()) {
|
|
return nil
|
|
}
|
|
|
|
return tx.Factory().UpdateSetAccessorDeclaration(
|
|
input,
|
|
tx.ensureModifiers(input.AsNode()),
|
|
input.Name(),
|
|
nil, // accessors shouldn't have type params
|
|
tx.updateAccessorParamList(input.AsNode(), tx.host.GetEffectiveDeclarationFlags(tx.EmitContext().ParseNode(input.AsNode()), ast.ModifierFlagsPrivate) != 0),
|
|
nil,
|
|
nil,
|
|
nil,
|
|
)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformGetAccesorDeclaration(input *ast.GetAccessorDeclaration) *ast.Node {
|
|
if ast.IsPrivateIdentifier(input.Name()) {
|
|
return nil
|
|
}
|
|
return tx.Factory().UpdateGetAccessorDeclaration(
|
|
input,
|
|
tx.ensureModifiers(input.AsNode()),
|
|
input.Name(),
|
|
nil, // accessors shouldn't have type params
|
|
tx.updateAccessorParamList(input.AsNode(), tx.host.GetEffectiveDeclarationFlags(tx.EmitContext().ParseNode(input.AsNode()), ast.ModifierFlagsPrivate) != 0),
|
|
tx.ensureType(input.AsNode(), false),
|
|
nil,
|
|
nil,
|
|
)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) updateAccessorParamList(input *ast.Node, isPrivate bool) *ast.ParameterList {
|
|
var newParams []*ast.Node
|
|
if !isPrivate {
|
|
thisParam := ast.GetThisParameter(input)
|
|
if thisParam != nil {
|
|
newParams = append(newParams, tx.ensureParameter(thisParam.AsParameterDeclaration()))
|
|
}
|
|
}
|
|
if ast.IsSetAccessorDeclaration(input) {
|
|
var valueParam *ast.Node
|
|
if !isPrivate {
|
|
if len(newParams) == 1 && len(input.AsSetAccessorDeclaration().Parameters.Nodes) >= 2 {
|
|
valueParam = tx.ensureParameter(input.AsSetAccessorDeclaration().Parameters.Nodes[1].AsParameterDeclaration())
|
|
} else if len(newParams) == 0 && len(input.AsSetAccessorDeclaration().Parameters.Nodes) >= 1 {
|
|
valueParam = tx.ensureParameter(input.AsSetAccessorDeclaration().Parameters.Nodes[0].AsParameterDeclaration())
|
|
}
|
|
}
|
|
if valueParam == nil {
|
|
// TODO: strada bug - no type printed on set accessor missing arg as though private
|
|
var t *ast.Node
|
|
if !isPrivate {
|
|
t = tx.Factory().NewKeywordExpression(ast.KindAnyKeyword)
|
|
}
|
|
valueParam = tx.Factory().NewParameterDeclaration(
|
|
nil,
|
|
nil,
|
|
tx.Factory().NewIdentifier("value"),
|
|
nil,
|
|
t,
|
|
nil,
|
|
)
|
|
}
|
|
newParams = append(newParams, valueParam)
|
|
}
|
|
return tx.Factory().NewNodeList(newParams)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformConstructorDeclaration(input *ast.ConstructorDeclaration) *ast.Node {
|
|
// A constructor declaration may not have a type annotation
|
|
return tx.Factory().UpdateConstructorDeclaration(
|
|
input,
|
|
tx.ensureModifiers(input.AsNode()),
|
|
nil, // no type params
|
|
tx.updateParamList(input.AsNode(), input.Parameters),
|
|
nil, // no return type
|
|
nil,
|
|
nil,
|
|
)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformConstructSignatureDeclaration(input *ast.ConstructSignatureDeclaration) *ast.Node {
|
|
return tx.Factory().UpdateConstructSignatureDeclaration(
|
|
input,
|
|
tx.ensureTypeParams(input.AsNode(), input.TypeParameters),
|
|
tx.updateParamList(input.AsNode(), input.Parameters),
|
|
tx.ensureType(input.AsNode(), false),
|
|
)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) omitPrivateMethodType(input *ast.Node) *ast.Node {
|
|
if input.Symbol() != nil && len(input.Symbol().Declarations) > 0 && input.Symbol().Declarations[0] != input {
|
|
return nil
|
|
} else {
|
|
return tx.Factory().NewPropertyDeclaration(
|
|
tx.ensureModifiers(input),
|
|
input.Name(),
|
|
nil,
|
|
nil,
|
|
nil,
|
|
)
|
|
}
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformMethodSignatureDeclaration(input *ast.MethodSignatureDeclaration) *ast.Node {
|
|
if tx.host.GetEffectiveDeclarationFlags(tx.EmitContext().ParseNode(input.AsNode()), ast.ModifierFlagsPrivate) != 0 {
|
|
return tx.omitPrivateMethodType(input.AsNode())
|
|
} else if ast.IsPrivateIdentifier(input.Name()) {
|
|
return nil
|
|
} else {
|
|
return tx.Factory().UpdateMethodSignatureDeclaration(
|
|
input,
|
|
tx.ensureModifiers(input.AsNode()),
|
|
input.Name(),
|
|
input.PostfixToken,
|
|
tx.ensureTypeParams(input.AsNode(), input.TypeParameters),
|
|
tx.updateParamList(input.AsNode(), input.Parameters),
|
|
tx.ensureType(input.AsNode(), false),
|
|
)
|
|
}
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformMethodDeclaration(input *ast.MethodDeclaration) *ast.Node {
|
|
if tx.host.GetEffectiveDeclarationFlags(tx.EmitContext().ParseNode(input.AsNode()), ast.ModifierFlagsPrivate) != 0 {
|
|
return tx.omitPrivateMethodType(input.AsNode())
|
|
} else if ast.IsPrivateIdentifier(input.Name()) {
|
|
return nil
|
|
} else {
|
|
return tx.Factory().UpdateMethodDeclaration(
|
|
input,
|
|
tx.ensureModifiers(input.AsNode()),
|
|
nil,
|
|
input.Name(),
|
|
input.PostfixToken,
|
|
tx.ensureTypeParams(input.AsNode(), input.TypeParameters),
|
|
tx.updateParamList(input.AsNode(), input.Parameters),
|
|
tx.ensureType(input.AsNode(), false),
|
|
nil,
|
|
nil,
|
|
)
|
|
}
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) visitDeclarationStatements(input *ast.Node) *ast.Node {
|
|
// !!! TODO: stripInternal support?
|
|
// if (shouldStripInternal(input)) return nil
|
|
switch input.Kind {
|
|
case ast.KindExportDeclaration:
|
|
if ast.IsSourceFile(input.Parent) {
|
|
tx.resultHasExternalModuleIndicator = true
|
|
}
|
|
tx.resultHasScopeMarker = true
|
|
// Rewrite external module names if necessary
|
|
return tx.Factory().UpdateExportDeclaration(
|
|
input.AsExportDeclaration(),
|
|
input.Modifiers(),
|
|
input.IsTypeOnly(),
|
|
input.AsExportDeclaration().ExportClause,
|
|
tx.rewriteModuleSpecifier(input, input.AsExportDeclaration().ModuleSpecifier),
|
|
tx.tryGetResolutionModeOverride(input.AsExportDeclaration().Attributes),
|
|
)
|
|
case ast.KindExportAssignment, ast.KindJSExportAssignment:
|
|
if ast.IsSourceFile(input.Parent) {
|
|
tx.resultHasExternalModuleIndicator = true
|
|
}
|
|
tx.resultHasScopeMarker = true
|
|
if input.AsExportAssignment().Expression.Kind == ast.KindIdentifier {
|
|
return input
|
|
}
|
|
// expression is non-identifier, create _default typed variable to reference
|
|
newId := tx.Factory().NewUniqueNameEx("_default", printer.AutoGenerateOptions{Flags: printer.GeneratedIdentifierFlagsOptimistic})
|
|
tx.state.getSymbolAccessibilityDiagnostic = func(_ printer.SymbolAccessibilityResult) *SymbolAccessibilityDiagnostic {
|
|
return &SymbolAccessibilityDiagnostic{
|
|
diagnosticMessage: diagnostics.Default_export_of_the_module_has_or_is_using_private_name_0,
|
|
errorNode: input,
|
|
}
|
|
}
|
|
tx.tracker.PushErrorFallbackNode(input)
|
|
type_ := tx.ensureType(input, false)
|
|
varDecl := tx.Factory().NewVariableDeclaration(newId, nil, type_, nil)
|
|
tx.tracker.PopErrorFallbackNode()
|
|
var modList *ast.ModifierList
|
|
if tx.needsDeclare {
|
|
modList = tx.Factory().NewModifierList([]*ast.Node{tx.Factory().NewModifier(ast.KindDeclareKeyword)})
|
|
} else {
|
|
modList = tx.Factory().NewModifierList([]*ast.Node{})
|
|
}
|
|
statement := tx.Factory().NewVariableStatement(modList, tx.Factory().NewVariableDeclarationList(ast.NodeFlagsConst, tx.Factory().NewNodeList([]*ast.Node{varDecl})))
|
|
|
|
assignment := tx.Factory().UpdateExportAssignment(input.AsExportAssignment(), input.Modifiers(), input.Type(), newId)
|
|
// Remove comments from the export declaration and copy them onto the synthetic _default declaration
|
|
tx.preserveJsDoc(statement, input)
|
|
tx.removeAllComments(assignment)
|
|
return tx.Factory().NewSyntaxList([]*ast.Node{statement, assignment})
|
|
default:
|
|
id := ast.GetNodeId(tx.EmitContext().MostOriginal(input))
|
|
if tx.lateStatementReplacementMap[id] == nil {
|
|
// Don't actually transform yet; just leave as original node - will be elided/swapped by late pass
|
|
tx.lateStatementReplacementMap[id] = tx.transformTopLevelDeclaration(input)
|
|
}
|
|
return input
|
|
}
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) rewriteModuleSpecifier(parent *ast.Node, input *ast.Node) *ast.Node {
|
|
if input == nil {
|
|
return nil
|
|
}
|
|
tx.resultHasExternalModuleIndicator = tx.resultHasExternalModuleIndicator || (parent.Kind != ast.KindModuleDeclaration && parent.Kind != ast.KindImportType)
|
|
if ast.IsStringLiteralLike(input) {
|
|
if tx.isBundledEmit {
|
|
// !!! TODO: support bundled emit specifier rewriting
|
|
}
|
|
}
|
|
return input
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) tryGetResolutionModeOverride(node *ast.Node) *ast.Node {
|
|
if node == nil {
|
|
return node
|
|
}
|
|
mode := tx.host.GetResolutionModeOverride(node)
|
|
if mode != core.ResolutionModeNone {
|
|
return node
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) preserveJsDoc(updated *ast.Node, original *ast.Node) {
|
|
// !!! TODO: JSDoc comment support
|
|
// if (hasJSDocNodes(updated) && hasJSDocNodes(original)) {
|
|
// updated.jsDoc = original.jsDoc;
|
|
// }
|
|
// return setCommentRange(updated, getCommentRange(original));
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) removeAllComments(node *ast.Node) {
|
|
tx.EmitContext().AddEmitFlags(node, printer.EFNoComments)
|
|
// !!! TODO: Also remove synthetic trailing/leading comments added by transforms
|
|
// emitNode.leadingComments = undefined;
|
|
// emitNode.trailingComments = undefined;
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) ensureType(node *ast.Node, ignorePrivate bool) *ast.Node {
|
|
if !ignorePrivate && tx.host.GetEffectiveDeclarationFlags(tx.EmitContext().ParseNode(node), ast.ModifierFlagsPrivate) != 0 {
|
|
// Private nodes emit no types (except private parameter properties, whose parameter types are actually visible)
|
|
return nil
|
|
}
|
|
|
|
if tx.shouldPrintWithInitializer(node) {
|
|
// Literal const declarations will have an initializer ensured rather than a type
|
|
return nil
|
|
}
|
|
|
|
// Should be removed createTypeOfDeclaration will actually now reuse the existing annotation so there is no real need to duplicate type walking
|
|
// Left in for now to minimize diff during syntactic type node builder refactor
|
|
if !ast.IsExportAssignment(node) && !ast.IsBindingElement(node) && node.Type() != nil && (!ast.IsParameter(node) || !tx.resolver.RequiresAddingImplicitUndefined(node, nil, tx.enclosingDeclaration)) {
|
|
return tx.Visitor().Visit(node.Type())
|
|
}
|
|
|
|
oldErrorNameNode := tx.state.errorNameNode
|
|
tx.state.errorNameNode = node.Name()
|
|
var oldDiag GetSymbolAccessibilityDiagnostic
|
|
if !tx.suppressNewDiagnosticContexts {
|
|
oldDiag = tx.state.getSymbolAccessibilityDiagnostic
|
|
if canProduceDiagnostics(node) {
|
|
tx.state.getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(node)
|
|
}
|
|
}
|
|
var typeNode *ast.Node
|
|
|
|
if hasInferredType(node) {
|
|
typeNode = tx.resolver.CreateTypeOfDeclaration(tx.EmitContext(), node, tx.enclosingDeclaration, declarationEmitNodeBuilderFlags, declarationEmitInternalNodeBuilderFlags, tx.tracker)
|
|
} else if ast.IsFunctionLike(node) {
|
|
typeNode = tx.resolver.CreateReturnTypeOfSignatureDeclaration(tx.EmitContext(), node, tx.enclosingDeclaration, declarationEmitNodeBuilderFlags, declarationEmitInternalNodeBuilderFlags, tx.tracker)
|
|
} else {
|
|
debug.AssertNever(node)
|
|
}
|
|
|
|
tx.state.errorNameNode = oldErrorNameNode
|
|
if !tx.suppressNewDiagnosticContexts {
|
|
tx.state.getSymbolAccessibilityDiagnostic = oldDiag
|
|
}
|
|
if typeNode == nil {
|
|
return tx.Factory().NewKeywordTypeNode(ast.KindAnyKeyword)
|
|
}
|
|
return typeNode
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) shouldPrintWithInitializer(node *ast.Node) bool {
|
|
return canHaveLiteralInitializer(tx.host, node) && node.Initializer() != nil && tx.resolver.IsLiteralConstDeclaration(tx.EmitContext().MostOriginal(node))
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) checkEntityNameVisibility(entityName *ast.Node, enclosingDeclaration *ast.Node) {
|
|
visibilityResult := tx.resolver.IsEntityNameVisible(entityName, enclosingDeclaration)
|
|
tx.tracker.handleSymbolAccessibilityError(visibilityResult)
|
|
}
|
|
|
|
// Transforms the direct child of a source file into zero or more replacement statements
|
|
func (tx *DeclarationTransformer) transformTopLevelDeclaration(input *ast.Node) *ast.Node {
|
|
if len(tx.state.lateMarkedStatements) > 0 {
|
|
// Remove duplicates of the current statement from the deferred work queue (this was done via orderedRemoveItem in strada - why? to ensure the same backing array? microop?)
|
|
tx.state.lateMarkedStatements = core.Filter(tx.state.lateMarkedStatements, func(node *ast.Node) bool { return node != input })
|
|
}
|
|
// !!! TODO: stripInternal support?
|
|
// if (shouldStripInternal(input)) return;
|
|
if input.Kind == ast.KindImportEqualsDeclaration {
|
|
return tx.transformImportEqualsDeclaration(input.AsImportEqualsDeclaration())
|
|
}
|
|
if input.Kind == ast.KindImportDeclaration || input.Kind == ast.KindJSImportDeclaration {
|
|
res := tx.transformImportDeclaration(input.AsImportDeclaration())
|
|
if res != nil && res.Kind != ast.KindImportDeclaration {
|
|
res := res.Clone(tx.Factory())
|
|
res.Kind = ast.KindImportDeclaration
|
|
return res
|
|
}
|
|
return res
|
|
}
|
|
if ast.IsDeclaration(input) && isDeclarationAndNotVisible(tx.EmitContext(), tx.resolver, input) {
|
|
return nil
|
|
}
|
|
|
|
// !!! TODO: JSDoc support
|
|
// if (isJSDocImportTag(input)) return;
|
|
|
|
// Elide implementation signatures from overload sets
|
|
if ast.IsFunctionLike(input) && tx.resolver.IsImplementationOfOverload(input) {
|
|
return nil
|
|
}
|
|
previousEnclosingDeclaration := tx.enclosingDeclaration
|
|
if isEnclosingDeclaration(input) {
|
|
tx.enclosingDeclaration = input
|
|
}
|
|
|
|
canProdiceDiagnostic := canProduceDiagnostics(input)
|
|
oldDiag := tx.state.getSymbolAccessibilityDiagnostic
|
|
oldName := tx.state.errorNameNode
|
|
if canProdiceDiagnostic {
|
|
tx.state.getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(input)
|
|
}
|
|
saveNeedsDeclare := tx.needsDeclare
|
|
|
|
var result *ast.Node
|
|
switch input.Kind {
|
|
case ast.KindTypeAliasDeclaration, ast.KindJSTypeAliasDeclaration:
|
|
result = tx.transformTypeAliasDeclaration(input.AsTypeAliasDeclaration())
|
|
case ast.KindInterfaceDeclaration:
|
|
result = tx.transformInterfaceDeclaration(input.AsInterfaceDeclaration())
|
|
case ast.KindFunctionDeclaration:
|
|
result = tx.transformFunctionDeclaration(input.AsFunctionDeclaration())
|
|
case ast.KindModuleDeclaration:
|
|
result = tx.transformModuleDeclaration(input.AsModuleDeclaration())
|
|
case ast.KindClassDeclaration:
|
|
result = tx.transformClassDeclaration(input.AsClassDeclaration())
|
|
case ast.KindVariableStatement:
|
|
result = tx.transformVariableStatement(input.AsVariableStatement())
|
|
case ast.KindEnumDeclaration:
|
|
result = tx.transformEnumDeclaration(input.AsEnumDeclaration())
|
|
default:
|
|
// Anything left unhandled is an error, so this should be unreachable
|
|
panic(fmt.Sprintf("Unhandled top-level node in declaration emit: %q", input.Kind))
|
|
}
|
|
|
|
tx.enclosingDeclaration = previousEnclosingDeclaration
|
|
tx.state.getSymbolAccessibilityDiagnostic = oldDiag
|
|
tx.needsDeclare = saveNeedsDeclare
|
|
tx.state.errorNameNode = oldName
|
|
return result
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformTypeAliasDeclaration(input *ast.TypeAliasDeclaration) *ast.Node {
|
|
tx.needsDeclare = false
|
|
return tx.Factory().UpdateTypeAliasDeclaration(
|
|
input,
|
|
tx.ensureModifiers(input.AsNode()),
|
|
input.Name(),
|
|
tx.Visitor().VisitNodes(input.TypeParameters),
|
|
tx.Visitor().Visit(input.Type),
|
|
)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformInterfaceDeclaration(input *ast.InterfaceDeclaration) *ast.Node {
|
|
return tx.Factory().UpdateInterfaceDeclaration(
|
|
input,
|
|
tx.ensureModifiers(input.AsNode()),
|
|
input.Name(),
|
|
tx.Visitor().VisitNodes(input.TypeParameters),
|
|
tx.Visitor().VisitNodes(input.HeritageClauses),
|
|
tx.Visitor().VisitNodes(input.Members),
|
|
)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformFunctionDeclaration(input *ast.FunctionDeclaration) *ast.Node {
|
|
return tx.Factory().UpdateFunctionDeclaration(
|
|
input,
|
|
tx.ensureModifiers(input.AsNode()),
|
|
nil,
|
|
input.Name(),
|
|
tx.ensureTypeParams(input.AsNode(), input.TypeParameters),
|
|
tx.updateParamList(input.AsNode(), input.Parameters),
|
|
tx.ensureType(input.AsNode(), false),
|
|
nil, /*fullSignature*/
|
|
nil,
|
|
)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformModuleDeclaration(input *ast.ModuleDeclaration) *ast.Node {
|
|
// !!! TODO: module declarations are now parsed into nested module objects with export modifiers
|
|
// It'd be good to collapse those back in the declaration output, but the AST can't represent the
|
|
// `namespace a.b.c` shape for the printer (without using invalid identifier names).
|
|
mods := tx.ensureModifiers(input.AsNode())
|
|
saveNeedsDeclare := tx.needsDeclare
|
|
tx.needsDeclare = false
|
|
inner := input.Body
|
|
keyword := input.Keyword
|
|
if keyword != ast.KindGlobalKeyword && (input.Name() == nil || !ast.IsStringLiteral(input.Name())) {
|
|
keyword = ast.KindNamespaceKeyword
|
|
}
|
|
|
|
if inner != nil && inner.Kind == ast.KindModuleBlock {
|
|
oldNeedsScopeFix := tx.needsScopeFixMarker
|
|
oldHasScopeFix := tx.resultHasScopeMarker
|
|
tx.resultHasScopeMarker = false
|
|
tx.needsScopeFixMarker = false
|
|
statements := tx.Visitor().VisitNodes(inner.AsModuleBlock().Statements)
|
|
lateStatements := tx.transformAndReplaceLatePaintedStatements(statements)
|
|
if input.Flags&ast.NodeFlagsAmbient != 0 {
|
|
tx.needsScopeFixMarker = false // If it was `declare`'d everything is implicitly exported already, ignore late printed "privates"
|
|
}
|
|
// With the final list of statements, there are 3 possibilities:
|
|
// 1. There's an export assignment or export declaration in the namespace - do nothing
|
|
// 2. Everything is exported and there are no export assignments or export declarations - strip all export modifiers
|
|
// 3. Some things are exported, some are not, and there's no marker - add an empty marker
|
|
if !ast.IsGlobalScopeAugmentation(input.AsNode()) && !tx.resultHasScopeMarker && !hasScopeMarker(lateStatements) {
|
|
if tx.needsScopeFixMarker {
|
|
lateStatements = tx.Factory().NewNodeList(append(lateStatements.Nodes, createEmptyExports(tx.Factory().AsNodeFactory())))
|
|
} else {
|
|
lateStatements = tx.EmitContext().NewNodeVisitor(tx.stripExportModifiers).VisitNodes(lateStatements)
|
|
}
|
|
}
|
|
|
|
body := tx.Factory().UpdateModuleBlock(inner.AsModuleBlock(), lateStatements)
|
|
tx.needsDeclare = saveNeedsDeclare
|
|
tx.needsScopeFixMarker = oldNeedsScopeFix
|
|
tx.resultHasScopeMarker = oldHasScopeFix
|
|
|
|
return tx.Factory().UpdateModuleDeclaration(
|
|
input,
|
|
mods,
|
|
keyword,
|
|
input.Name(),
|
|
body,
|
|
)
|
|
}
|
|
if inner != nil {
|
|
// trigger visit. ignore result (is deferred, so is just inner unless elided)
|
|
tx.Visitor().Visit(inner)
|
|
// eagerly transform nested namespaces (the nesting doesn't need any elision or painting done)
|
|
original := tx.EmitContext().MostOriginal(inner)
|
|
id := ast.GetNodeId(original)
|
|
body, _ := tx.lateStatementReplacementMap[id]
|
|
delete(tx.lateStatementReplacementMap, id)
|
|
return tx.Factory().UpdateModuleDeclaration(
|
|
input,
|
|
mods,
|
|
keyword,
|
|
input.Name(),
|
|
body,
|
|
)
|
|
}
|
|
return tx.Factory().UpdateModuleDeclaration(
|
|
input,
|
|
mods,
|
|
keyword,
|
|
input.Name(),
|
|
nil,
|
|
)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) stripExportModifiers(statement *ast.Node) *ast.Node {
|
|
if statement == nil {
|
|
return nil
|
|
}
|
|
if ast.IsImportEqualsDeclaration(statement) || tx.host.GetEffectiveDeclarationFlags(tx.EmitContext().ParseNode(statement), ast.ModifierFlagsDefault) != 0 || !ast.CanHaveModifiers(statement) {
|
|
// `export import` statements should remain as-is, as imports are _not_ implicitly exported in an ambient namespace
|
|
// Likewise, `export default` classes and the like and just be `default`, so we preserve their `export` modifiers, too
|
|
return statement
|
|
}
|
|
|
|
oldFlags := ast.GetCombinedModifierFlags(statement)
|
|
if oldFlags&ast.ModifierFlagsExport == 0 {
|
|
return statement
|
|
}
|
|
newFlags := oldFlags & (ast.ModifierFlagsAll ^ ast.ModifierFlagsExport)
|
|
modifiers := ast.CreateModifiersFromModifierFlags(newFlags, tx.Factory().NewModifier)
|
|
return ast.ReplaceModifiers(tx.Factory().AsNodeFactory(), statement, tx.Factory().NewModifierList(modifiers))
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformClassDeclaration(input *ast.ClassDeclaration) *ast.Node {
|
|
tx.state.errorNameNode = input.Name()
|
|
tx.tracker.PushErrorFallbackNode(input.AsNode())
|
|
defer tx.tracker.PopErrorFallbackNode()
|
|
|
|
modifiers := tx.ensureModifiers(input.AsNode())
|
|
typeParameters := tx.ensureTypeParams(input.AsNode(), input.TypeParameters)
|
|
ctor := getFirstConstructorWithBody(input.AsNode())
|
|
var parameterProperties []*ast.Node
|
|
if ctor != nil {
|
|
oldDiag := tx.state.getSymbolAccessibilityDiagnostic
|
|
for _, param := range ctor.AsConstructorDeclaration().Parameters.Nodes {
|
|
if !ast.HasSyntacticModifier(param, ast.ModifierFlagsParameterPropertyModifier) {
|
|
continue
|
|
}
|
|
// !!! TODO: stripInternal support?
|
|
// if (shouldStripInternal(param)) { continue }
|
|
tx.state.getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(param)
|
|
if param.Name().Kind == ast.KindIdentifier {
|
|
updated := tx.Factory().NewPropertyDeclaration(
|
|
tx.ensureModifiers(param),
|
|
param.Name(),
|
|
param.AsParameterDeclaration().QuestionToken,
|
|
tx.ensureType(param, false),
|
|
tx.ensureNoInitializer(param),
|
|
)
|
|
tx.preserveJsDoc(updated, param)
|
|
parameterProperties = append(parameterProperties, updated)
|
|
} else {
|
|
// Pattern - this is currently an error, but we emit declarations for it somewhat correctly
|
|
// !!! is this worth reimplementing? We never made it not-an-error
|
|
}
|
|
}
|
|
tx.state.getSymbolAccessibilityDiagnostic = oldDiag
|
|
}
|
|
|
|
// When the class has at least one private identifier, create a unique constant identifier to retain the nominal typing behavior
|
|
// Prevents other classes with the same public members from being used in place of the current class
|
|
var privateIdentifier *ast.Node
|
|
if core.Some(input.Members.Nodes, func(member *ast.Node) bool { return member.Name() != nil && ast.IsPrivateIdentifier(member.Name()) }) {
|
|
privateIdentifier = tx.Factory().NewPropertyDeclaration(
|
|
nil,
|
|
tx.Factory().NewPrivateIdentifier("#private"),
|
|
nil,
|
|
nil,
|
|
nil,
|
|
)
|
|
}
|
|
|
|
lateIndexes := tx.resolver.CreateLateBoundIndexSignatures(
|
|
tx.EmitContext(),
|
|
input.AsNode(),
|
|
tx.enclosingDeclaration,
|
|
declarationEmitNodeBuilderFlags,
|
|
declarationEmitInternalNodeBuilderFlags,
|
|
tx.tracker,
|
|
)
|
|
|
|
memberNodes := make([]*ast.Node, 0, len(input.Members.Nodes))
|
|
if privateIdentifier != nil {
|
|
memberNodes = append(memberNodes, privateIdentifier)
|
|
}
|
|
memberNodes = append(memberNodes, lateIndexes...)
|
|
memberNodes = append(memberNodes, parameterProperties...)
|
|
visitResult := tx.Visitor().VisitNodes(input.Members)
|
|
if visitResult != nil && len(visitResult.Nodes) > 0 {
|
|
memberNodes = append(memberNodes, visitResult.Nodes...)
|
|
}
|
|
members := tx.Factory().NewNodeList(memberNodes)
|
|
|
|
extendsClause := getEffectiveBaseTypeNode(input.AsNode())
|
|
|
|
if extendsClause != nil && !ast.IsEntityNameExpression(extendsClause.AsExpressionWithTypeArguments().Expression) && extendsClause.AsExpressionWithTypeArguments().Expression.Kind != ast.KindNullKeyword {
|
|
oldId := "default"
|
|
if ast.NodeIsPresent(input.Name()) && ast.IsIdentifier(input.Name()) && len(input.Name().AsIdentifier().Text) > 0 {
|
|
oldId = input.Name().AsIdentifier().Text
|
|
}
|
|
newId := tx.Factory().NewUniqueNameEx(oldId+"_base", printer.AutoGenerateOptions{Flags: printer.GeneratedIdentifierFlagsOptimistic})
|
|
tx.state.getSymbolAccessibilityDiagnostic = func(_ printer.SymbolAccessibilityResult) *SymbolAccessibilityDiagnostic {
|
|
return &SymbolAccessibilityDiagnostic{
|
|
diagnosticMessage: diagnostics.X_extends_clause_of_exported_class_0_has_or_is_using_private_name_1,
|
|
errorNode: extendsClause,
|
|
typeName: input.Name(),
|
|
}
|
|
}
|
|
|
|
varDecl := tx.Factory().NewVariableDeclaration(
|
|
newId,
|
|
nil,
|
|
tx.resolver.CreateTypeOfExpression(tx.EmitContext(), extendsClause.Expression(), input.AsNode(), declarationEmitNodeBuilderFlags, declarationEmitInternalNodeBuilderFlags, tx.tracker),
|
|
nil,
|
|
)
|
|
var mods *ast.ModifierList
|
|
if tx.needsDeclare {
|
|
mods = tx.Factory().NewModifierList([]*ast.Node{tx.Factory().NewModifier(ast.KindDeclareKeyword)})
|
|
}
|
|
statement := tx.Factory().NewVariableStatement(
|
|
mods,
|
|
tx.Factory().NewVariableDeclarationList(ast.NodeFlagsConst, tx.Factory().NewNodeList([]*ast.Node{varDecl})),
|
|
)
|
|
newHeritageClause := tx.Factory().UpdateHeritageClause(
|
|
extendsClause.Parent.AsHeritageClause(),
|
|
tx.Factory().NewNodeList([]*ast.Node{
|
|
tx.Factory().UpdateExpressionWithTypeArguments(
|
|
extendsClause.AsExpressionWithTypeArguments(),
|
|
newId,
|
|
tx.Visitor().VisitNodes(extendsClause.AsExpressionWithTypeArguments().TypeArguments),
|
|
),
|
|
}),
|
|
)
|
|
retainedHeritageClauses := tx.Visitor().VisitNodes(input.HeritageClauses) // should just be `implements`
|
|
heritageList := []*ast.Node{
|
|
newHeritageClause,
|
|
}
|
|
if retainedHeritageClauses != nil && len(retainedHeritageClauses.Nodes) > 0 {
|
|
heritageList = append(heritageList, retainedHeritageClauses.Nodes...)
|
|
}
|
|
heritageClauses := tx.Factory().NewNodeList(heritageList)
|
|
|
|
return tx.Factory().NewSyntaxList([]*ast.Node{
|
|
statement,
|
|
tx.Factory().UpdateClassDeclaration(
|
|
input,
|
|
modifiers,
|
|
input.Name(),
|
|
typeParameters,
|
|
heritageClauses,
|
|
members,
|
|
),
|
|
})
|
|
}
|
|
|
|
return tx.Factory().UpdateClassDeclaration(
|
|
input,
|
|
modifiers,
|
|
input.Name(),
|
|
typeParameters,
|
|
tx.Visitor().VisitNodes(input.HeritageClauses),
|
|
members,
|
|
)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformVariableStatement(input *ast.VariableStatement) *ast.Node {
|
|
visible := false
|
|
for _, decl := range input.DeclarationList.AsVariableDeclarationList().Declarations.Nodes {
|
|
visible = getBindingNameVisible(tx.resolver, decl)
|
|
if visible {
|
|
break
|
|
}
|
|
}
|
|
if !visible {
|
|
return nil
|
|
}
|
|
|
|
nodes := tx.Visitor().VisitNodes(input.DeclarationList.AsVariableDeclarationList().Declarations)
|
|
if nodes != nil && len(nodes.Nodes) == 0 {
|
|
return nil
|
|
}
|
|
|
|
modifiers := tx.ensureModifiers(input.AsNode())
|
|
|
|
var declList *ast.Node
|
|
if ast.IsVarUsing(input.DeclarationList) || ast.IsVarAwaitUsing(input.DeclarationList) {
|
|
declList = tx.Factory().NewVariableDeclarationList(ast.NodeFlagsConst, nodes)
|
|
tx.EmitContext().SetOriginal(declList, input.DeclarationList)
|
|
tx.EmitContext().SetCommentRange(declList, input.DeclarationList.Loc)
|
|
declList.Loc = input.DeclarationList.Loc
|
|
} else {
|
|
declList = tx.Factory().UpdateVariableDeclarationList(input.DeclarationList.AsVariableDeclarationList(), nodes)
|
|
}
|
|
return tx.Factory().UpdateVariableStatement(input, modifiers, declList)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformEnumDeclaration(input *ast.EnumDeclaration) *ast.Node {
|
|
return tx.Factory().UpdateEnumDeclaration(
|
|
input,
|
|
tx.ensureModifiers(input.AsNode()),
|
|
input.Name(),
|
|
tx.Factory().NewNodeList(core.MapNonNil(input.Members.Nodes, func(m *ast.Node) *ast.Node {
|
|
// !!! TODO: stripInternal support?
|
|
// if (shouldStripInternal(m)) return;
|
|
|
|
// !!! TODO: isolatedDeclarations support
|
|
// if (
|
|
// isolatedDeclarations && m.initializer && enumValue?.hasExternalReferences &&
|
|
// // This will be its own compiler error instead, so don't report.
|
|
// !isComputedPropertyName(m.name)
|
|
// ) {
|
|
// context.addDiagnostic(createDiagnosticForNode(m, Diagnostics.Enum_member_initializers_must_be_computable_without_references_to_external_symbols_with_isolatedDeclarations));
|
|
// }
|
|
|
|
// Rewrite enum values to their constants, if available
|
|
enumValue := tx.resolver.GetEnumMemberValue(m)
|
|
var newInitializer *ast.Node
|
|
switch value := enumValue.Value.(type) {
|
|
case jsnum.Number:
|
|
if value >= 0 {
|
|
newInitializer = tx.Factory().NewNumericLiteral(value.String())
|
|
} else {
|
|
newInitializer = tx.Factory().NewPrefixUnaryExpression(
|
|
ast.KindMinusToken,
|
|
tx.Factory().NewNumericLiteral((-value).String()),
|
|
)
|
|
}
|
|
case string:
|
|
newInitializer = tx.Factory().NewStringLiteral(value)
|
|
default:
|
|
// nil
|
|
newInitializer = nil
|
|
}
|
|
result := tx.Factory().UpdateEnumMember(m.AsEnumMember(), m.Name(), newInitializer)
|
|
tx.preserveJsDoc(result, m)
|
|
return result
|
|
})),
|
|
)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) ensureModifiers(node *ast.Node) *ast.ModifierList {
|
|
currentFlags := tx.host.GetEffectiveDeclarationFlags(tx.EmitContext().ParseNode(node), ast.ModifierFlagsAll)
|
|
newFlags := tx.ensureModifierFlags(node)
|
|
if currentFlags == newFlags {
|
|
// Elide decorators
|
|
mods := node.Modifiers()
|
|
if mods == nil {
|
|
return mods
|
|
}
|
|
return tx.Factory().NewModifierList(core.Filter(mods.Nodes, ast.IsModifier))
|
|
}
|
|
result := ast.CreateModifiersFromModifierFlags(newFlags, tx.Factory().NewModifier)
|
|
if len(result) == 0 {
|
|
return nil
|
|
}
|
|
return tx.Factory().NewModifierList(result)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) ensureModifierFlags(node *ast.Node) ast.ModifierFlags {
|
|
mask := ast.ModifierFlagsAll ^ (ast.ModifierFlagsPublic | ast.ModifierFlagsAsync | ast.ModifierFlagsOverride) // No async and override modifiers in declaration files
|
|
additions := ast.ModifierFlagsNone
|
|
if tx.needsDeclare && !isAlwaysType(node) {
|
|
additions = ast.ModifierFlagsAmbient
|
|
}
|
|
parentIsFile := node.Parent.Kind == ast.KindSourceFile
|
|
if !parentIsFile || (tx.isBundledEmit && parentIsFile && ast.IsExternalModule(node.Parent.AsSourceFile())) {
|
|
mask ^= ast.ModifierFlagsAmbient
|
|
additions = ast.ModifierFlagsNone
|
|
}
|
|
return maskModifierFlags(tx.host, node, mask, additions)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) ensureTypeParams(node *ast.Node, params *ast.TypeParameterList) *ast.TypeParameterList {
|
|
if tx.host.GetEffectiveDeclarationFlags(tx.EmitContext().ParseNode(node), ast.ModifierFlagsPrivate) != 0 {
|
|
return nil
|
|
}
|
|
var typeParameters *ast.TypeParameterList
|
|
if typeParameters = tx.Visitor().VisitNodes(params); typeParameters != nil {
|
|
return typeParameters
|
|
}
|
|
oldErrorNameNode := tx.state.errorNameNode
|
|
tx.state.errorNameNode = node.Name()
|
|
var oldDiag GetSymbolAccessibilityDiagnostic
|
|
if !tx.suppressNewDiagnosticContexts {
|
|
oldDiag = tx.state.getSymbolAccessibilityDiagnostic
|
|
if canProduceDiagnostics(node) {
|
|
tx.state.getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(node)
|
|
}
|
|
}
|
|
|
|
if data := node.FunctionLikeData(); data != nil && data.FullSignature != nil {
|
|
if nodes := tx.resolver.CreateTypeParametersOfSignatureDeclaration(tx.EmitContext(), node, tx.enclosingDeclaration, declarationEmitNodeBuilderFlags, declarationEmitInternalNodeBuilderFlags, tx.tracker); nodes != nil {
|
|
typeParameters = &ast.TypeParameterList{
|
|
Loc: node.Loc,
|
|
Nodes: nodes,
|
|
}
|
|
}
|
|
}
|
|
|
|
tx.state.errorNameNode = oldErrorNameNode
|
|
if !tx.suppressNewDiagnosticContexts {
|
|
tx.state.getSymbolAccessibilityDiagnostic = oldDiag
|
|
}
|
|
return typeParameters
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) updateParamList(node *ast.Node, params *ast.ParameterList) *ast.ParameterList {
|
|
if tx.host.GetEffectiveDeclarationFlags(tx.EmitContext().ParseNode(node), ast.ModifierFlagsPrivate) != 0 || len(params.Nodes) == 0 {
|
|
return tx.Factory().NewNodeList([]*ast.Node{})
|
|
}
|
|
results := make([]*ast.Node, len(params.Nodes))
|
|
for i, p := range params.Nodes {
|
|
results[i] = tx.ensureParameter(p.AsParameterDeclaration())
|
|
}
|
|
return tx.Factory().NewNodeList(results)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) ensureParameter(p *ast.ParameterDeclaration) *ast.Node {
|
|
oldDiag := tx.state.getSymbolAccessibilityDiagnostic
|
|
if !tx.suppressNewDiagnosticContexts {
|
|
tx.state.getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(p.AsNode())
|
|
}
|
|
var questionToken *ast.TokenNode
|
|
if tx.resolver.IsOptionalParameter(p.AsNode()) {
|
|
if p.QuestionToken != nil {
|
|
questionToken = p.QuestionToken
|
|
} else {
|
|
questionToken = tx.Factory().NewToken(ast.KindQuestionToken)
|
|
}
|
|
}
|
|
result := tx.Factory().UpdateParameterDeclaration(
|
|
p,
|
|
nil,
|
|
p.DotDotDotToken,
|
|
tx.filterBindingPatternInitializers(p.Name()),
|
|
questionToken,
|
|
tx.ensureType(p.AsNode(), true),
|
|
tx.ensureNoInitializer(p.AsNode()),
|
|
)
|
|
tx.state.getSymbolAccessibilityDiagnostic = oldDiag
|
|
return result
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) ensureNoInitializer(node *ast.Node) *ast.Node {
|
|
if tx.shouldPrintWithInitializer(node) {
|
|
unwrappedInitializer := unwrapParenthesizedExpression(node.Initializer())
|
|
if !isPrimitiveLiteralValue(unwrappedInitializer, true) {
|
|
tx.tracker.ReportInferenceFallback(node)
|
|
}
|
|
return tx.resolver.CreateLiteralConstValue(tx.EmitContext(), tx.EmitContext().ParseNode(node), tx.tracker)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) filterBindingPatternInitializers(node *ast.Node) *ast.Node {
|
|
if node.Kind == ast.KindIdentifier {
|
|
return node
|
|
} else {
|
|
// TODO: visitor to avoid always making new nodes?
|
|
elements := make([]*ast.Node, 0, len(node.AsBindingPattern().Elements.Nodes))
|
|
for _, elem := range node.AsBindingPattern().Elements.Nodes {
|
|
if elem.Kind == ast.KindOmittedExpression {
|
|
elements = append(elements, elem)
|
|
continue
|
|
}
|
|
if elem.PropertyName() != nil && ast.IsComputedPropertyName(elem.PropertyName()) && ast.IsEntityNameExpression(elem.PropertyName().Expression()) {
|
|
tx.checkEntityNameVisibility(elem.PropertyName().Expression(), tx.enclosingDeclaration)
|
|
}
|
|
if elem.Name() == nil {
|
|
elements = append(elements, elem)
|
|
continue
|
|
}
|
|
|
|
elements = append(elements, tx.Factory().UpdateBindingElement(
|
|
elem.AsBindingElement(),
|
|
elem.AsBindingElement().DotDotDotToken,
|
|
elem.PropertyName(),
|
|
tx.filterBindingPatternInitializers(elem.Name()),
|
|
nil,
|
|
))
|
|
}
|
|
elemList := tx.Factory().NewNodeList(elements)
|
|
return tx.Factory().UpdateBindingPattern(node.AsBindingPattern(), elemList)
|
|
}
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformImportEqualsDeclaration(decl *ast.ImportEqualsDeclaration) *ast.Node {
|
|
if !tx.resolver.IsDeclarationVisible(decl.AsNode()) {
|
|
return nil
|
|
}
|
|
if decl.ModuleReference.Kind == ast.KindExternalModuleReference {
|
|
// Rewrite external module names if necessary
|
|
specifier := ast.GetExternalModuleImportEqualsDeclarationExpression(decl.AsNode())
|
|
return tx.Factory().UpdateImportEqualsDeclaration(
|
|
decl,
|
|
decl.Modifiers(),
|
|
decl.IsTypeOnly,
|
|
decl.Name(),
|
|
tx.Factory().UpdateExternalModuleReference(decl.ModuleReference.AsExternalModuleReference(), tx.rewriteModuleSpecifier(decl.AsNode(), specifier)),
|
|
)
|
|
} else {
|
|
oldDiag := tx.state.getSymbolAccessibilityDiagnostic
|
|
tx.state.getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(decl.AsNode())
|
|
tx.checkEntityNameVisibility(decl.ModuleReference, tx.enclosingDeclaration)
|
|
tx.state.getSymbolAccessibilityDiagnostic = oldDiag
|
|
return decl.AsNode()
|
|
}
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformImportDeclaration(decl *ast.ImportDeclaration) *ast.Node {
|
|
if decl.ImportClause == nil {
|
|
// import "mod" - possibly needed for side effects? (global interface patches, module augmentations, etc)
|
|
return tx.Factory().UpdateImportDeclaration(
|
|
decl,
|
|
decl.Modifiers(),
|
|
decl.ImportClause,
|
|
tx.rewriteModuleSpecifier(decl.AsNode(), decl.ModuleSpecifier),
|
|
tx.tryGetResolutionModeOverride(decl.Attributes),
|
|
)
|
|
}
|
|
phaseModifier := decl.ImportClause.AsImportClause().PhaseModifier
|
|
if phaseModifier == ast.KindDeferKeyword {
|
|
phaseModifier = ast.KindUnknown
|
|
}
|
|
// The `importClause` visibility corresponds to the default's visibility.
|
|
var visibleDefaultBinding *ast.Node
|
|
if decl.ImportClause != nil && decl.ImportClause.Name() != nil && tx.resolver.IsDeclarationVisible(decl.ImportClause) {
|
|
visibleDefaultBinding = decl.ImportClause.Name()
|
|
}
|
|
if decl.ImportClause.AsImportClause().NamedBindings == nil {
|
|
// No named bindings (either namespace or list), meaning the import is just default or should be elided
|
|
if visibleDefaultBinding == nil {
|
|
return nil
|
|
}
|
|
return tx.Factory().UpdateImportDeclaration(
|
|
decl,
|
|
decl.Modifiers(),
|
|
tx.Factory().UpdateImportClause(
|
|
decl.ImportClause.AsImportClause(),
|
|
phaseModifier,
|
|
visibleDefaultBinding,
|
|
/*namedBindings*/ nil,
|
|
),
|
|
tx.rewriteModuleSpecifier(decl.AsNode(), decl.ModuleSpecifier),
|
|
tx.tryGetResolutionModeOverride(decl.Attributes),
|
|
)
|
|
}
|
|
if decl.ImportClause.AsImportClause().NamedBindings.Kind == ast.KindNamespaceImport {
|
|
// Namespace import (optionally with visible default)
|
|
var namedBindings *ast.Node
|
|
if tx.resolver.IsDeclarationVisible(decl.ImportClause.AsImportClause().NamedBindings) {
|
|
namedBindings = decl.ImportClause.AsImportClause().NamedBindings
|
|
}
|
|
if visibleDefaultBinding == nil && namedBindings == nil {
|
|
return nil
|
|
}
|
|
return tx.Factory().UpdateImportDeclaration(
|
|
decl,
|
|
decl.Modifiers(),
|
|
tx.Factory().UpdateImportClause(
|
|
decl.ImportClause.AsImportClause(),
|
|
phaseModifier,
|
|
visibleDefaultBinding,
|
|
namedBindings,
|
|
),
|
|
tx.rewriteModuleSpecifier(decl.AsNode(), decl.ModuleSpecifier),
|
|
tx.tryGetResolutionModeOverride(decl.Attributes),
|
|
)
|
|
}
|
|
// Named imports (optionally with visible default)
|
|
bindingList := core.Filter(
|
|
decl.ImportClause.AsImportClause().NamedBindings.AsNamedImports().Elements.Nodes,
|
|
func(b *ast.Node) bool {
|
|
return tx.resolver.IsDeclarationVisible(b)
|
|
},
|
|
)
|
|
if len(bindingList) > 0 || visibleDefaultBinding != nil {
|
|
var namedImports *ast.Node
|
|
if len(bindingList) > 0 {
|
|
namedImports = tx.Factory().UpdateNamedImports(
|
|
decl.ImportClause.AsImportClause().NamedBindings.AsNamedImports(),
|
|
tx.Factory().NewNodeList(bindingList),
|
|
)
|
|
}
|
|
return tx.Factory().UpdateImportDeclaration(
|
|
decl,
|
|
decl.Modifiers(),
|
|
tx.Factory().UpdateImportClause(
|
|
decl.ImportClause.AsImportClause(),
|
|
phaseModifier,
|
|
visibleDefaultBinding,
|
|
namedImports,
|
|
),
|
|
tx.rewriteModuleSpecifier(decl.AsNode(), decl.ModuleSpecifier),
|
|
tx.tryGetResolutionModeOverride(decl.Attributes),
|
|
)
|
|
}
|
|
// Augmentation of export depends on import
|
|
if tx.resolver.IsImportRequiredByAugmentation(decl) {
|
|
// IsolatedDeclarations support
|
|
// if (isolatedDeclarations) {
|
|
// context.addDiagnostic(createDiagnosticForNode(decl, Diagnostics.Declaration_emit_for_this_file_requires_preserving_this_import_for_augmentations_This_is_not_supported_with_isolatedDeclarations));
|
|
// }
|
|
return tx.Factory().UpdateImportDeclaration(
|
|
decl,
|
|
decl.Modifiers(),
|
|
/*importClause*/ nil,
|
|
tx.rewriteModuleSpecifier(decl.AsNode(), decl.ModuleSpecifier),
|
|
tx.tryGetResolutionModeOverride(decl.Attributes),
|
|
)
|
|
}
|
|
// Nothing visible
|
|
return nil
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformJSDocTypeExpression(input *ast.JSDocTypeExpression) *ast.Node {
|
|
return tx.Visitor().Visit(input.Type)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformJSDocTypeLiteral(input *ast.JSDocTypeLiteral) *ast.Node {
|
|
members, _ := tx.Visitor().VisitSlice(input.JSDocPropertyTags)
|
|
replacement := tx.Factory().NewTypeLiteralNode(tx.Factory().NewNodeList(members))
|
|
tx.EmitContext().SetOriginal(replacement, input.AsNode())
|
|
return replacement
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformJSDocPropertyTag(input *ast.JSDocPropertyTag) *ast.Node {
|
|
replacement := tx.Factory().NewPropertySignatureDeclaration(
|
|
nil,
|
|
tx.Visitor().Visit(input.TagName),
|
|
nil,
|
|
tx.Visitor().Visit(input.TypeExpression),
|
|
nil,
|
|
)
|
|
tx.EmitContext().SetOriginal(replacement, input.AsNode())
|
|
return replacement
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformJSDocAllType(input *ast.JSDocAllType) *ast.Node {
|
|
replacement := tx.Factory().NewKeywordTypeNode(ast.KindAnyKeyword)
|
|
tx.EmitContext().SetOriginal(replacement, input.AsNode())
|
|
return replacement
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformJSDocNullableType(input *ast.JSDocNullableType) *ast.Node {
|
|
replacement := tx.Factory().NewUnionTypeNode(tx.Factory().NewNodeList([]*ast.Node{
|
|
tx.Visitor().Visit(input.Type),
|
|
tx.Factory().NewLiteralTypeNode(tx.Factory().NewKeywordExpression(ast.KindNullKeyword)),
|
|
}))
|
|
tx.EmitContext().SetOriginal(replacement, input.AsNode())
|
|
return replacement
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformJSDocNonNullableType(input *ast.JSDocNonNullableType) *ast.Node {
|
|
return tx.Visitor().Visit(input.Type)
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformJSDocVariadicType(input *ast.JSDocVariadicType) *ast.Node {
|
|
replacement := tx.Factory().NewArrayTypeNode(tx.Visitor().Visit(input.Type))
|
|
tx.EmitContext().SetOriginal(replacement, input.AsNode())
|
|
return replacement
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformJSDocOptionalType(input *ast.JSDocOptionalType) *ast.Node {
|
|
replacement := tx.Factory().NewUnionTypeNode(tx.Factory().NewNodeList([]*ast.Node{
|
|
tx.Visitor().Visit(input.Type),
|
|
tx.Factory().NewKeywordTypeNode(ast.KindUndefinedKeyword),
|
|
}))
|
|
tx.EmitContext().SetOriginal(replacement, input.AsNode())
|
|
return replacement
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) visitExpressionStatement(node *ast.ExpressionStatement) *ast.Node {
|
|
expression := node.Expression
|
|
if expression == nil {
|
|
return nil
|
|
}
|
|
|
|
if expression.Kind == ast.KindBinaryExpression &&
|
|
ast.GetAssignmentDeclarationKind(expression.AsBinaryExpression()) == ast.JSDeclarationKindProperty {
|
|
return tx.transformExpandoAssignment(expression.AsBinaryExpression())
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformExpandoAssignment(node *ast.BinaryExpression) *ast.Node {
|
|
left := node.Left
|
|
|
|
symbol := node.Symbol
|
|
if symbol == nil || symbol.Flags&ast.SymbolFlagsAssignment == 0 {
|
|
return nil
|
|
}
|
|
|
|
ns := ast.GetLeftmostAccessExpression(left)
|
|
if ns == nil || ns.Kind != ast.KindIdentifier {
|
|
return nil
|
|
}
|
|
|
|
declaration := tx.resolver.GetReferencedValueDeclaration(ns)
|
|
if declaration == nil {
|
|
return nil
|
|
}
|
|
|
|
host := declaration.Symbol()
|
|
if host == nil {
|
|
return nil
|
|
}
|
|
|
|
name := tx.Factory().NewIdentifier(ns.Text())
|
|
property := tx.tryGetPropertyName(left)
|
|
if property == "" || !scanner.IsIdentifierText(property, core.LanguageVariantStandard) {
|
|
return nil
|
|
}
|
|
|
|
tx.transformExpandoHost(name, declaration)
|
|
|
|
if ast.IsFunctionDeclaration(declaration) && !shouldEmitFunctionProperties(declaration.AsFunctionDeclaration()) {
|
|
return nil
|
|
}
|
|
|
|
isNonContextualKeywordName := ast.IsNonContextualKeyword(scanner.StringToToken(property))
|
|
exportName := core.IfElse(isNonContextualKeywordName, tx.Factory().NewGeneratedNameForNode(left), tx.Factory().NewIdentifier(property))
|
|
|
|
synthesizedNamespace := tx.Factory().NewModuleDeclaration(nil /*modifiers*/, ast.KindNamespaceKeyword, name, tx.Factory().NewModuleBlock(tx.Factory().NewNodeList([]*ast.Node{})))
|
|
synthesizedNamespace.Parent = tx.enclosingDeclaration
|
|
|
|
declarationData := synthesizedNamespace.DeclarationData()
|
|
declarationData.Symbol = host
|
|
|
|
containerData := synthesizedNamespace.LocalsContainerData()
|
|
containerData.Locals = make(ast.SymbolTable, 0)
|
|
|
|
saveDiag := tx.state.getSymbolAccessibilityDiagnostic
|
|
tx.state.getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(node.AsNode())
|
|
t := tx.resolver.CreateTypeOfExpression(tx.EmitContext(), left, synthesizedNamespace, declarationEmitNodeBuilderFlags, declarationEmitInternalNodeBuilderFlags|nodebuilder.InternalFlagsNoSyntacticPrinter, tx.tracker)
|
|
tx.state.getSymbolAccessibilityDiagnostic = saveDiag
|
|
|
|
statements := []*ast.Statement{
|
|
tx.Factory().NewVariableStatement(
|
|
nil, /*modifiers*/
|
|
tx.Factory().NewVariableDeclarationList(
|
|
ast.NodeFlagsNone,
|
|
tx.Factory().NewNodeList([]*ast.Node{
|
|
tx.Factory().NewVariableDeclaration(exportName, nil /*exclamationToken*/, t, nil /*initializer*/),
|
|
}),
|
|
),
|
|
),
|
|
}
|
|
|
|
if isNonContextualKeywordName {
|
|
namedExports := tx.Factory().NewNamedExports(tx.Factory().NewNodeList(
|
|
[]*ast.Node{
|
|
tx.Factory().NewExportSpecifier(false /*isTypeOnly*/, exportName, tx.Factory().NewIdentifier(left.Name().Text())),
|
|
},
|
|
))
|
|
statements = append(statements, tx.Factory().NewExportDeclaration(nil /*modifiers*/, false /*isTypeOnly*/, namedExports, nil /*moduleSpecifier*/, nil /*attributes*/))
|
|
}
|
|
|
|
flags := tx.host.GetEffectiveDeclarationFlags(tx.EmitContext().ParseNode(declaration), ast.ModifierFlagsAll)
|
|
modifierFlags := ast.ModifierFlagsAmbient
|
|
|
|
if flags&ast.ModifierFlagsExport != 0 {
|
|
if flags&ast.ModifierFlagsDefault == 0 {
|
|
modifierFlags |= ast.ModifierFlagsExport
|
|
}
|
|
tx.resultHasScopeMarker = true
|
|
tx.resultHasExternalModuleIndicator = true
|
|
}
|
|
|
|
return tx.Factory().NewModuleDeclaration(tx.Factory().NewModifierList(ast.CreateModifiersFromModifierFlags(modifierFlags, tx.Factory().NewModifier)), ast.KindNamespaceKeyword, name, tx.Factory().NewModuleBlock(tx.Factory().NewNodeList(statements)))
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) transformExpandoHost(name *ast.Node, declaration *ast.Declaration) {
|
|
root := core.IfElse(ast.IsVariableDeclaration(declaration), declaration.Parent.Parent, declaration)
|
|
id := ast.GetNodeId(tx.EmitContext().MostOriginal(root))
|
|
|
|
if tx.expandoHosts.Has(id) {
|
|
return
|
|
}
|
|
|
|
saveNeedsDeclare := tx.needsDeclare
|
|
tx.needsDeclare = true
|
|
|
|
modifierFlags := tx.ensureModifierFlags(root)
|
|
defaultExport := modifierFlags&ast.ModifierFlagsExport != 0 && modifierFlags&ast.ModifierFlagsDefault != 0
|
|
|
|
tx.needsDeclare = saveNeedsDeclare
|
|
|
|
if defaultExport {
|
|
modifierFlags |= ast.ModifierFlagsAmbient
|
|
modifierFlags ^= ast.ModifierFlagsDefault
|
|
modifierFlags ^= ast.ModifierFlagsExport
|
|
}
|
|
|
|
modifiers := tx.Factory().NewModifierList(ast.CreateModifiersFromModifierFlags(modifierFlags, tx.Factory().NewModifier))
|
|
replacement := make([]*ast.Node, 0)
|
|
|
|
if ast.IsFunctionDeclaration(declaration) {
|
|
typeParameters, parameters, asteriskToken := extractExpandoHostParams(declaration)
|
|
replacement = append(replacement, tx.Factory().UpdateFunctionDeclaration(declaration.AsFunctionDeclaration(), modifiers, asteriskToken, declaration.Name(), tx.ensureTypeParams(declaration, typeParameters), tx.updateParamList(declaration, parameters), tx.ensureType(declaration, false), nil /*fullSignature*/, nil /*body*/))
|
|
} else if ast.IsVariableDeclaration(declaration) && ast.IsFunctionExpressionOrArrowFunction(declaration.Initializer()) {
|
|
fn := declaration.Initializer()
|
|
typeParameters, parameters, asteriskToken := extractExpandoHostParams(fn)
|
|
replacement = append(replacement, tx.Factory().NewFunctionDeclaration(modifiers, asteriskToken, tx.Factory().NewIdentifier(name.Text()), tx.ensureTypeParams(fn, typeParameters), tx.updateParamList(fn, parameters), tx.ensureType(fn, false), nil /*fullSignature*/, nil /*body*/))
|
|
} else {
|
|
return
|
|
}
|
|
|
|
if defaultExport {
|
|
replacement = append(replacement, tx.Factory().NewExportAssignment(nil /*modifiers*/, false /*isExportEquals*/, nil /*typeNode*/, name))
|
|
}
|
|
|
|
tx.expandoHosts.Add(id)
|
|
tx.lateStatementReplacementMap[id] = tx.Factory().NewSyntaxList(replacement)
|
|
}
|
|
|
|
func extractExpandoHostParams(node *ast.Node) (typeParameters *ast.TypeParameterList, parameters *ast.ParameterList, asteriskToken *ast.TokenNode) {
|
|
switch node.Kind {
|
|
case ast.KindFunctionExpression:
|
|
fn := node.AsFunctionExpression()
|
|
return fn.TypeParameters, fn.Parameters, fn.AsteriskToken
|
|
case ast.KindArrowFunction:
|
|
fn := node.AsArrowFunction()
|
|
return fn.TypeParameters, fn.Parameters, fn.AsteriskToken
|
|
default:
|
|
fn := node.AsFunctionDeclaration()
|
|
return fn.TypeParameters, fn.Parameters, fn.AsteriskToken
|
|
}
|
|
}
|
|
|
|
func (tx *DeclarationTransformer) tryGetPropertyName(node *ast.Node) string {
|
|
if ast.IsElementAccessExpression(node) {
|
|
return tx.resolver.GetElementAccessExpressionName(node.AsElementAccessExpression())
|
|
}
|
|
if ast.IsPropertyAccessExpression(node) {
|
|
return node.Name().Text()
|
|
}
|
|
return ""
|
|
}
|