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 "" }