• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*@internal*/
2namespace ts {
3    export function getDeclarationDiagnostics(host: EmitHost, resolver: EmitResolver, file: SourceFile | undefined): DiagnosticWithLocation[] | undefined {
4        const compilerOptions = host.getCompilerOptions();
5        const result = transformNodes(resolver, host, factory, compilerOptions, file ? [file] : filter(host.getSourceFiles(), isSourceFileNotJson), [transformDeclarations], /*allowDtsFiles*/ false);
6        return result.diagnostics;
7    }
8
9    function hasInternalAnnotation(range: CommentRange, currentSourceFile: SourceFile) {
10        const comment = currentSourceFile.text.substring(range.pos, range.end);
11        return stringContains(comment, "@internal");
12    }
13
14    export function isInternalDeclaration(node: Node, currentSourceFile: SourceFile) {
15        const parseTreeNode = getParseTreeNode(node);
16        if (parseTreeNode && parseTreeNode.kind === SyntaxKind.Parameter) {
17            const paramIdx = (parseTreeNode.parent as SignatureDeclaration).parameters.indexOf(parseTreeNode as ParameterDeclaration);
18            const previousSibling = paramIdx > 0 ? (parseTreeNode.parent as SignatureDeclaration).parameters[paramIdx - 1] : undefined;
19            const text = currentSourceFile.text;
20            const commentRanges = previousSibling
21                ? concatenate(
22                    // to handle
23                    // ... parameters, /* @internal */
24                    // public param: string
25                    getTrailingCommentRanges(text, skipTrivia(text, previousSibling.end + 1, /* stopAfterLineBreak */ false, /* stopAtComments */ true)),
26                    getLeadingCommentRanges(text, node.pos)
27                )
28                : getTrailingCommentRanges(text, skipTrivia(text, node.pos, /* stopAfterLineBreak */ false, /* stopAtComments */ true));
29            return commentRanges && commentRanges.length && hasInternalAnnotation(last(commentRanges), currentSourceFile);
30        }
31        const leadingCommentRanges = parseTreeNode && getLeadingCommentRangesOfNode(parseTreeNode, currentSourceFile);
32        return !!forEach(leadingCommentRanges, range => {
33            return hasInternalAnnotation(range, currentSourceFile);
34        });
35    }
36
37    const declarationEmitNodeBuilderFlags =
38        NodeBuilderFlags.MultilineObjectLiterals |
39        NodeBuilderFlags.WriteClassExpressionAsTypeLiteral |
40        NodeBuilderFlags.UseTypeOfFunction |
41        NodeBuilderFlags.UseStructuralFallback |
42        NodeBuilderFlags.AllowEmptyTuple |
43        NodeBuilderFlags.GenerateNamesForShadowedTypeParams |
44        NodeBuilderFlags.NoTruncation;
45
46    /**
47     * Transforms a ts file into a .d.ts or .d.ets file
48     * This process requires type information, which is retrieved through the emit resolver. Because of this,
49     * in many places this transformer assumes it will be operating on parse tree nodes directly.
50     * This means that _no transforms should be allowed to occur before this one_.
51     */
52    export function transformDeclarations(context: TransformationContext) {
53        const throwDiagnostic = () => Debug.fail("Diagnostic emitted without context");
54        let getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic = throwDiagnostic;
55        let needsDeclare = true;
56        let isBundledEmit = false;
57        let resultHasExternalModuleIndicator = false;
58        let needsScopeFixMarker = false;
59        let resultHasScopeMarker = false;
60        let enclosingDeclaration: Node;
61        let necessaryTypeReferences: Set<string> | undefined;
62        let lateMarkedStatements: LateVisibilityPaintedStatement[] | undefined;
63        let lateStatementReplacementMap: ESMap<NodeId, VisitResult<LateVisibilityPaintedStatement | ExportAssignment>>;
64        let suppressNewDiagnosticContexts: boolean;
65        let exportedModulesFromDeclarationEmit: Symbol[] | undefined;
66
67        const { factory } = context;
68        const host = context.getEmitHost();
69        const symbolTracker: SymbolTracker = {
70            trackSymbol,
71            reportInaccessibleThisError,
72            reportInaccessibleUniqueSymbolError,
73            reportCyclicStructureError,
74            reportPrivateInBaseOfClassExpression,
75            reportLikelyUnsafeImportRequiredError,
76            reportTruncationError,
77            moduleResolverHost: host,
78            trackReferencedAmbientModule,
79            trackExternalModuleSymbolOfImportTypeNode,
80            reportNonlocalAugmentation
81        };
82        let errorNameNode: DeclarationName | undefined;
83        let errorFallbackNode: Declaration | undefined;
84
85        let currentSourceFile: SourceFile;
86        let refs: ESMap<NodeId, SourceFile>;
87        let libs: ESMap<string, boolean>;
88        let emittedImports: readonly AnyImportSyntax[] | undefined; // must be declared in container so it can be `undefined` while transformer's first pass
89        const resolver = context.getEmitResolver();
90        const options = context.getCompilerOptions();
91        const { noResolve, stripInternal } = options;
92        return transformRoot;
93
94        function recordTypeReferenceDirectivesIfNecessary(typeReferenceDirectives: readonly string[] | undefined): void {
95            if (!typeReferenceDirectives) {
96                return;
97            }
98            necessaryTypeReferences = necessaryTypeReferences || new Set();
99            for (const ref of typeReferenceDirectives) {
100                necessaryTypeReferences.add(ref);
101            }
102        }
103
104        function trackReferencedAmbientModule(node: ModuleDeclaration, symbol: Symbol) {
105            // If it is visible via `// <reference types="..."/>`, then we should just use that
106            const directives = resolver.getTypeReferenceDirectivesForSymbol(symbol, SymbolFlags.All);
107            if (length(directives)) {
108                return recordTypeReferenceDirectivesIfNecessary(directives);
109            }
110            // Otherwise we should emit a path-based reference
111            const container = getSourceFileOfNode(node);
112            refs.set(getOriginalNodeId(container), container);
113        }
114
115        function handleSymbolAccessibilityError(symbolAccessibilityResult: SymbolAccessibilityResult) {
116            if (symbolAccessibilityResult.accessibility === SymbolAccessibility.Accessible) {
117                // Add aliases back onto the possible imports list if they're not there so we can try them again with updated visibility info
118                if (symbolAccessibilityResult && symbolAccessibilityResult.aliasesToMakeVisible) {
119                    if (!lateMarkedStatements) {
120                        lateMarkedStatements = symbolAccessibilityResult.aliasesToMakeVisible;
121                    }
122                    else {
123                        for (const ref of symbolAccessibilityResult.aliasesToMakeVisible) {
124                            pushIfUnique(lateMarkedStatements, ref);
125                        }
126                    }
127                }
128
129                // TODO: Do all these accessibility checks inside/after the first pass in the checker when declarations are enabled, if possible
130            }
131            else {
132                // Report error
133                const errorInfo = getSymbolAccessibilityDiagnostic(symbolAccessibilityResult);
134                if (errorInfo) {
135                    if (errorInfo.typeName) {
136                        context.addDiagnostic(createDiagnosticForNode(symbolAccessibilityResult.errorNode || errorInfo.errorNode,
137                            errorInfo.diagnosticMessage,
138                            getTextOfNode(errorInfo.typeName),
139                            symbolAccessibilityResult.errorSymbolName,
140                            symbolAccessibilityResult.errorModuleName));
141                    }
142                    else {
143                        context.addDiagnostic(createDiagnosticForNode(symbolAccessibilityResult.errorNode || errorInfo.errorNode,
144                            errorInfo.diagnosticMessage,
145                            symbolAccessibilityResult.errorSymbolName,
146                            symbolAccessibilityResult.errorModuleName));
147                    }
148                }
149            }
150        }
151
152        function trackExternalModuleSymbolOfImportTypeNode(symbol: Symbol) {
153            if (!isBundledEmit) {
154                (exportedModulesFromDeclarationEmit || (exportedModulesFromDeclarationEmit = [])).push(symbol);
155            }
156        }
157
158        function trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) {
159            if (symbol.flags & SymbolFlags.TypeParameter) return;
160            handleSymbolAccessibilityError(resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning, /*shouldComputeAliasesToMakeVisible*/ true));
161            recordTypeReferenceDirectivesIfNecessary(resolver.getTypeReferenceDirectivesForSymbol(symbol, meaning));
162        }
163
164        function reportPrivateInBaseOfClassExpression(propertyName: string) {
165            if (errorNameNode || errorFallbackNode) {
166                context.addDiagnostic(
167                    createDiagnosticForNode((errorNameNode || errorFallbackNode)!, Diagnostics.Property_0_of_exported_class_expression_may_not_be_private_or_protected, propertyName));
168            }
169        }
170
171        function reportInaccessibleUniqueSymbolError() {
172            if (errorNameNode) {
173                context.addDiagnostic(createDiagnosticForNode(errorNameNode, Diagnostics.The_inferred_type_of_0_references_an_inaccessible_1_type_A_type_annotation_is_necessary,
174                    declarationNameToString(errorNameNode),
175                    "unique symbol"));
176            }
177        }
178
179        function reportCyclicStructureError() {
180            if (errorNameNode) {
181                context.addDiagnostic(createDiagnosticForNode(errorNameNode, Diagnostics.The_inferred_type_of_0_references_a_type_with_a_cyclic_structure_which_cannot_be_trivially_serialized_A_type_annotation_is_necessary,
182                    declarationNameToString(errorNameNode)));
183            }
184        }
185
186        function reportInaccessibleThisError() {
187            if (errorNameNode) {
188                context.addDiagnostic(createDiagnosticForNode(errorNameNode, Diagnostics.The_inferred_type_of_0_references_an_inaccessible_1_type_A_type_annotation_is_necessary,
189                    declarationNameToString(errorNameNode),
190                    "this"));
191            }
192        }
193
194        function reportLikelyUnsafeImportRequiredError(specifier: string) {
195            if (errorNameNode) {
196                context.addDiagnostic(createDiagnosticForNode(errorNameNode, Diagnostics.The_inferred_type_of_0_cannot_be_named_without_a_reference_to_1_This_is_likely_not_portable_A_type_annotation_is_necessary,
197                    declarationNameToString(errorNameNode),
198                    specifier));
199            }
200        }
201
202        function reportTruncationError() {
203            if (errorNameNode || errorFallbackNode) {
204                context.addDiagnostic(createDiagnosticForNode((errorNameNode || errorFallbackNode)!, Diagnostics.The_inferred_type_of_this_node_exceeds_the_maximum_length_the_compiler_will_serialize_An_explicit_type_annotation_is_needed));
205            }
206        }
207
208        function reportNonlocalAugmentation(containingFile: SourceFile, parentSymbol: Symbol, symbol: Symbol) {
209            const primaryDeclaration = find(parentSymbol.declarations, d => getSourceFileOfNode(d) === containingFile)!;
210            const augmentingDeclarations = filter(symbol.declarations, d => getSourceFileOfNode(d) !== containingFile);
211            for (const augmentations of augmentingDeclarations) {
212                context.addDiagnostic(addRelatedInfo(
213                    createDiagnosticForNode(augmentations, Diagnostics.Declaration_augments_declaration_in_another_file_This_cannot_be_serialized),
214                    createDiagnosticForNode(primaryDeclaration, Diagnostics.This_is_the_declaration_being_augmented_Consider_moving_the_augmenting_declaration_into_the_same_file)
215                ));
216            }
217        }
218
219        function transformDeclarationsForJS(sourceFile: SourceFile, bundled?: boolean) {
220            const oldDiag = getSymbolAccessibilityDiagnostic;
221            getSymbolAccessibilityDiagnostic = (s) => (s.errorNode && canProduceDiagnostics(s.errorNode) ? createGetSymbolAccessibilityDiagnosticForNode(s.errorNode)(s) : ({
222                diagnosticMessage: s.errorModuleName
223                    ? Diagnostics.Declaration_emit_for_this_file_requires_using_private_name_0_from_module_1_An_explicit_type_annotation_may_unblock_declaration_emit
224                    : Diagnostics.Declaration_emit_for_this_file_requires_using_private_name_0_An_explicit_type_annotation_may_unblock_declaration_emit,
225                errorNode: s.errorNode || sourceFile
226            }));
227            const result = resolver.getDeclarationStatementsForSourceFile(sourceFile, declarationEmitNodeBuilderFlags, symbolTracker, bundled);
228            getSymbolAccessibilityDiagnostic = oldDiag;
229            return result;
230        }
231
232        function transformRoot(node: Bundle): Bundle;
233        function transformRoot(node: SourceFile): SourceFile;
234        function transformRoot(node: SourceFile | Bundle): SourceFile | Bundle;
235        function transformRoot(node: SourceFile | Bundle) {
236            if (node.kind === SyntaxKind.SourceFile && node.isDeclarationFile) {
237                return node;
238            }
239
240            if (node.kind === SyntaxKind.Bundle) {
241                isBundledEmit = true;
242                refs = new Map();
243                libs = new Map();
244                let hasNoDefaultLib = false;
245                const bundle = factory.createBundle(map(node.sourceFiles,
246                    sourceFile => {
247                        if (sourceFile.isDeclarationFile) return undefined!; // Omit declaration files from bundle results, too // TODO: GH#18217
248                        hasNoDefaultLib = hasNoDefaultLib || sourceFile.hasNoDefaultLib;
249                        currentSourceFile = sourceFile;
250                        enclosingDeclaration = sourceFile;
251                        lateMarkedStatements = undefined;
252                        suppressNewDiagnosticContexts = false;
253                        lateStatementReplacementMap = new Map();
254                        getSymbolAccessibilityDiagnostic = throwDiagnostic;
255                        needsScopeFixMarker = false;
256                        resultHasScopeMarker = false;
257                        collectReferences(sourceFile, refs);
258                        collectLibs(sourceFile, libs);
259                        if (isExternalOrCommonJsModule(sourceFile) || isJsonSourceFile(sourceFile)) {
260                            resultHasExternalModuleIndicator = false; // unused in external module bundle emit (all external modules are within module blocks, therefore are known to be modules)
261                            needsDeclare = false;
262                            const statements = isSourceFileJS(sourceFile) ? factory.createNodeArray(transformDeclarationsForJS(sourceFile, /*bundled*/ true)) : visitNodes(sourceFile.statements, visitDeclarationStatements);
263                            const newFile = factory.updateSourceFile(sourceFile, [factory.createModuleDeclaration(
264                                [],
265                                [factory.createModifier(SyntaxKind.DeclareKeyword)],
266                                factory.createStringLiteral(getResolvedExternalModuleName(context.getEmitHost(), sourceFile)),
267                                factory.createModuleBlock(setTextRange(factory.createNodeArray(transformAndReplaceLatePaintedStatements(statements)), sourceFile.statements))
268                            )], /*isDeclarationFile*/ true, /*referencedFiles*/ [], /*typeReferences*/ [], /*hasNoDefaultLib*/ false, /*libReferences*/ []);
269                            return newFile;
270                        }
271                        needsDeclare = true;
272                        const updated = isSourceFileJS(sourceFile) ? factory.createNodeArray(transformDeclarationsForJS(sourceFile)) : visitNodes(sourceFile.statements, visitDeclarationStatements);
273                        return factory.updateSourceFile(sourceFile, transformAndReplaceLatePaintedStatements(updated), /*isDeclarationFile*/ true, /*referencedFiles*/ [], /*typeReferences*/ [], /*hasNoDefaultLib*/ false, /*libReferences*/ []);
274                    }
275                ), mapDefined(node.prepends, prepend => {
276                    if (prepend.kind === SyntaxKind.InputFiles) {
277                        const sourceFile = createUnparsedSourceFile(prepend, "dts", stripInternal);
278                        hasNoDefaultLib = hasNoDefaultLib || !!sourceFile.hasNoDefaultLib;
279                        collectReferences(sourceFile, refs);
280                        recordTypeReferenceDirectivesIfNecessary(sourceFile.typeReferenceDirectives);
281                        collectLibs(sourceFile, libs);
282                        return sourceFile;
283                    }
284                    return prepend;
285                }));
286                bundle.syntheticFileReferences = [];
287                bundle.syntheticTypeReferences = getFileReferencesForUsedTypeReferences();
288                bundle.syntheticLibReferences = getLibReferences();
289                bundle.hasNoDefaultLib = hasNoDefaultLib;
290                const outputFilePath = getDirectoryPath(normalizeSlashes(getOutputPathsFor(node, host, /*forceDtsPaths*/ true).declarationFilePath!));
291                const referenceVisitor = mapReferencesIntoArray(bundle.syntheticFileReferences as FileReference[], outputFilePath);
292                refs.forEach(referenceVisitor);
293                return bundle;
294            }
295
296            // Single source file
297            needsDeclare = true;
298            needsScopeFixMarker = false;
299            resultHasScopeMarker = false;
300            enclosingDeclaration = node;
301            currentSourceFile = node;
302            getSymbolAccessibilityDiagnostic = throwDiagnostic;
303            isBundledEmit = false;
304            resultHasExternalModuleIndicator = false;
305            suppressNewDiagnosticContexts = false;
306            lateMarkedStatements = undefined;
307            lateStatementReplacementMap = new Map();
308            necessaryTypeReferences = undefined;
309            refs = collectReferences(currentSourceFile, new Map());
310            libs = collectLibs(currentSourceFile, new Map());
311            const references: FileReference[] = [];
312            const outputFilePath = getDirectoryPath(normalizeSlashes(getOutputPathsFor(node, host, /*forceDtsPaths*/ true).declarationFilePath!));
313            const referenceVisitor = mapReferencesIntoArray(references, outputFilePath);
314            let combinedStatements: NodeArray<Statement>;
315            if (isSourceFileJS(currentSourceFile)) {
316                combinedStatements = factory.createNodeArray(transformDeclarationsForJS(node));
317                refs.forEach(referenceVisitor);
318                emittedImports = filter(combinedStatements, isAnyImportSyntax);
319            }
320            else {
321                const statements = visitNodes(node.statements, visitDeclarationStatements);
322                combinedStatements = setTextRange(factory.createNodeArray(transformAndReplaceLatePaintedStatements(statements)), node.statements);
323                refs.forEach(referenceVisitor);
324                emittedImports = filter(combinedStatements, isAnyImportSyntax);
325                if (isExternalModule(node) && (!resultHasExternalModuleIndicator || (needsScopeFixMarker && !resultHasScopeMarker))) {
326                    combinedStatements = setTextRange(factory.createNodeArray([...combinedStatements, createEmptyExports(factory)]), combinedStatements);
327                }
328            }
329            const updated = factory.updateSourceFile(node, combinedStatements, /*isDeclarationFile*/ true, references, getFileReferencesForUsedTypeReferences(), node.hasNoDefaultLib, getLibReferences());
330            updated.exportedModulesFromDeclarationEmit = exportedModulesFromDeclarationEmit;
331            return updated;
332
333            function getLibReferences() {
334                return map(arrayFrom(libs.keys()), lib => ({ fileName: lib, pos: -1, end: -1 }));
335            }
336
337            function getFileReferencesForUsedTypeReferences() {
338                return necessaryTypeReferences ? mapDefined(arrayFrom(necessaryTypeReferences.keys()), getFileReferenceForTypeName) : [];
339            }
340
341            function getFileReferenceForTypeName(typeName: string): FileReference | undefined {
342                // Elide type references for which we have imports
343                if (emittedImports) {
344                    for (const importStatement of emittedImports) {
345                        if (isImportEqualsDeclaration(importStatement) && isExternalModuleReference(importStatement.moduleReference)) {
346                            const expr = importStatement.moduleReference.expression;
347                            if (isStringLiteralLike(expr) && expr.text === typeName) {
348                                return undefined;
349                            }
350                        }
351                        else if (isImportDeclaration(importStatement) && isStringLiteral(importStatement.moduleSpecifier) && importStatement.moduleSpecifier.text === typeName) {
352                            return undefined;
353                        }
354                    }
355                }
356                return { fileName: typeName, pos: -1, end: -1 };
357            }
358
359            function mapReferencesIntoArray(references: FileReference[], outputFilePath: string): (file: SourceFile) => void {
360                return file => {
361                    let declFileName: string;
362                    if (file.isDeclarationFile) { // Neither decl files or js should have their refs changed
363                        declFileName = file.fileName;
364                    }
365                    else {
366                        if (isBundledEmit && contains((node as Bundle).sourceFiles, file)) return; // Omit references to files which are being merged
367                        const paths = getOutputPathsFor(file, host, /*forceDtsPaths*/ true);
368                        declFileName = paths.declarationFilePath || paths.jsFilePath || file.fileName;
369                    }
370
371                    if (declFileName) {
372                        const specifier = moduleSpecifiers.getModuleSpecifier(
373                            // We pathify the baseUrl since we pathify the other paths here, so we can still easily check if the other paths are within the baseUrl
374                            // TODO: Should we _always_ be pathifying the baseUrl as we read it in?
375                            { ...options, baseUrl: options.baseUrl && toPath(options.baseUrl, host.getCurrentDirectory(), host.getCanonicalFileName) },
376                            currentSourceFile,
377                            toPath(outputFilePath, host.getCurrentDirectory(), host.getCanonicalFileName),
378                            toPath(declFileName, host.getCurrentDirectory(), host.getCanonicalFileName),
379                            host,
380                            /*preferences*/ undefined,
381                        );
382                        if (!pathIsRelative(specifier)) {
383                            // If some compiler option/symlink/whatever allows access to the file containing the ambient module declaration
384                            // via a non-relative name, emit a type reference directive to that non-relative name, rather than
385                            // a relative path to the declaration file
386                            recordTypeReferenceDirectivesIfNecessary([specifier]);
387                            return;
388                        }
389
390                        let fileName = getRelativePathToDirectoryOrUrl(
391                            outputFilePath,
392                            declFileName,
393                            host.getCurrentDirectory(),
394                            host.getCanonicalFileName,
395                            /*isAbsolutePathAnUrl*/ false
396                        );
397                        if (startsWith(fileName, "./") && hasExtension(fileName)) {
398                            fileName = fileName.substring(2);
399                        }
400
401                        // omit references to files from node_modules or oh_modules (npm may disambiguate module
402                        // references when installing this package, making the path is unreliable).
403                        if (isNodeModulesReference(fileName) || (isOhpm(options.packageManagerType) && isOHModulesReference(fileName))) {
404                            return;
405                        }
406
407                        references.push({ pos: -1, end: -1, fileName });
408                    }
409                };
410            }
411        }
412
413        function isNodeModulesReference(fileName: string): boolean {
414            return startsWith(fileName, "node_modules/") || pathContainsNodeModules(fileName);
415        }
416
417        function isOHModulesReference(fileName: string): boolean {
418            return startsWith(fileName, "oh_modules/") || pathContainsOHModules(fileName);
419        }
420
421        function collectReferences(sourceFile: SourceFile | UnparsedSource, ret: ESMap<NodeId, SourceFile>) {
422            if (noResolve || (!isUnparsedSource(sourceFile) && isSourceFileJS(sourceFile))) return ret;
423            forEach(sourceFile.referencedFiles, f => {
424                const elem = host.getSourceFileFromReference(sourceFile, f);
425                if (elem) {
426                    ret.set(getOriginalNodeId(elem), elem);
427                }
428            });
429            return ret;
430        }
431
432        function collectLibs(sourceFile: SourceFile | UnparsedSource, ret: ESMap<string, boolean>) {
433            forEach(sourceFile.libReferenceDirectives, ref => {
434                const lib = host.getLibFileFromReference(ref);
435                if (lib) {
436                    ret.set(toFileNameLowerCase(ref.fileName), true);
437                }
438            });
439            return ret;
440        }
441
442        function filterBindingPatternInitializers(name: BindingName) {
443            if (name.kind === SyntaxKind.Identifier) {
444                return name;
445            }
446            else {
447                if (name.kind === SyntaxKind.ArrayBindingPattern) {
448                    return factory.updateArrayBindingPattern(name, visitNodes(name.elements, visitBindingElement));
449                }
450                else {
451                    return factory.updateObjectBindingPattern(name, visitNodes(name.elements, visitBindingElement));
452                }
453            }
454
455            function visitBindingElement<T extends ArrayBindingElement>(elem: T): T;
456            function visitBindingElement(elem: ArrayBindingElement): ArrayBindingElement {
457                if (elem.kind === SyntaxKind.OmittedExpression) {
458                    return elem;
459                }
460                return factory.updateBindingElement(elem, elem.dotDotDotToken, elem.propertyName, filterBindingPatternInitializers(elem.name), shouldPrintWithInitializer(elem) ? elem.initializer : undefined);
461            }
462        }
463
464        function ensureParameter(p: ParameterDeclaration, modifierMask?: ModifierFlags, type?: TypeNode): ParameterDeclaration {
465            let oldDiag: typeof getSymbolAccessibilityDiagnostic | undefined;
466            if (!suppressNewDiagnosticContexts) {
467                oldDiag = getSymbolAccessibilityDiagnostic;
468                getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(p);
469            }
470            const newParam = factory.updateParameterDeclaration(
471                p,
472                /*decorators*/ undefined,
473                maskModifiers(p, modifierMask),
474                p.dotDotDotToken,
475                filterBindingPatternInitializers(p.name),
476                resolver.isOptionalParameter(p) ? (p.questionToken || factory.createToken(SyntaxKind.QuestionToken)) : undefined,
477                ensureType(p, type || p.type, /*ignorePrivate*/ true), // Ignore private param props, since this type is going straight back into a param
478                ensureNoInitializer(p)
479            );
480            if (!suppressNewDiagnosticContexts) {
481                getSymbolAccessibilityDiagnostic = oldDiag!;
482            }
483            return newParam;
484        }
485
486        function shouldPrintWithInitializer(node: Node) {
487            return canHaveLiteralInitializer(node) && resolver.isLiteralConstDeclaration(getParseTreeNode(node) as CanHaveLiteralInitializer); // TODO: Make safe
488        }
489
490        function ensureNoInitializer(node: CanHaveLiteralInitializer) {
491            if (shouldPrintWithInitializer(node)) {
492                return resolver.createLiteralConstValue(getParseTreeNode(node) as CanHaveLiteralInitializer, symbolTracker); // TODO: Make safe
493            }
494            return undefined;
495        }
496
497        type HasInferredType =
498            | FunctionDeclaration
499            | MethodDeclaration
500            | GetAccessorDeclaration
501            | SetAccessorDeclaration
502            | BindingElement
503            | ConstructSignatureDeclaration
504            | VariableDeclaration
505            | MethodSignature
506            | CallSignatureDeclaration
507            | ParameterDeclaration
508            | PropertyDeclaration
509            | PropertySignature;
510
511        function ensureType(node: HasInferredType, type: TypeNode | undefined, ignorePrivate?: boolean): TypeNode | undefined {
512            if (!ignorePrivate && hasEffectiveModifier(node, ModifierFlags.Private)) {
513                // Private nodes emit no types (except private parameter properties, whose parameter types are actually visible)
514                return;
515            }
516            if (shouldPrintWithInitializer(node)) {
517                // Literal const declarations will have an initializer ensured rather than a type
518                return;
519            }
520            if (type !== undefined && isTypeReferenceNode(type) && type.typeName.virtual) {
521                return;
522            }
523            const shouldUseResolverType = node.kind === SyntaxKind.Parameter &&
524                (resolver.isRequiredInitializedParameter(node) ||
525                 resolver.isOptionalUninitializedParameterProperty(node));
526            if (type && !shouldUseResolverType) {
527                return visitNode(type, visitDeclarationSubtree);
528            }
529            if (!getParseTreeNode(node)) {
530                return type ? visitNode(type, visitDeclarationSubtree) : factory.createKeywordTypeNode(SyntaxKind.AnyKeyword);
531            }
532            if (node.kind === SyntaxKind.SetAccessor) {
533                // Set accessors with no associated type node (from it's param or get accessor return) are `any` since they are never contextually typed right now
534                // (The inferred type here will be void, but the old declaration emitter printed `any`, so this replicates that)
535                return factory.createKeywordTypeNode(SyntaxKind.AnyKeyword);
536            }
537            errorNameNode = node.name;
538            let oldDiag: typeof getSymbolAccessibilityDiagnostic;
539            if (!suppressNewDiagnosticContexts) {
540                oldDiag = getSymbolAccessibilityDiagnostic;
541                getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(node);
542            }
543            if (node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement) {
544                return cleanup(resolver.createTypeOfDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker));
545            }
546            if (node.kind === SyntaxKind.Parameter
547                || node.kind === SyntaxKind.PropertyDeclaration
548                || node.kind === SyntaxKind.PropertySignature) {
549                if (!node.initializer) return cleanup(resolver.createTypeOfDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker, shouldUseResolverType));
550                return cleanup(resolver.createTypeOfDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker, shouldUseResolverType) || resolver.createTypeOfExpression(node.initializer, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker));
551            }
552            return cleanup(resolver.createReturnTypeOfSignatureDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker));
553
554            function cleanup(returnValue: TypeNode | undefined) {
555                errorNameNode = undefined;
556                if (!suppressNewDiagnosticContexts) {
557                    getSymbolAccessibilityDiagnostic = oldDiag;
558                }
559                return returnValue || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword);
560            }
561        }
562
563        function isDeclarationAndNotVisible(node: NamedDeclaration) {
564            node = getParseTreeNode(node) as NamedDeclaration;
565            switch (node.kind) {
566                case SyntaxKind.FunctionDeclaration:
567                case SyntaxKind.ModuleDeclaration:
568                case SyntaxKind.InterfaceDeclaration:
569                case SyntaxKind.ClassDeclaration:
570                case SyntaxKind.StructDeclaration:
571                case SyntaxKind.TypeAliasDeclaration:
572                case SyntaxKind.EnumDeclaration:
573                    return !resolver.isDeclarationVisible(node);
574                // The following should be doing their own visibility checks based on filtering their members
575                case SyntaxKind.VariableDeclaration:
576                    return !getBindingNameVisible(node as VariableDeclaration);
577                case SyntaxKind.ImportEqualsDeclaration:
578                case SyntaxKind.ImportDeclaration:
579                case SyntaxKind.ExportDeclaration:
580                case SyntaxKind.ExportAssignment:
581                    return false;
582            }
583            return false;
584        }
585
586        function getBindingNameVisible(elem: BindingElement | VariableDeclaration | OmittedExpression): boolean {
587            if (isOmittedExpression(elem)) {
588                return false;
589            }
590            if (isBindingPattern(elem.name)) {
591                // If any child binding pattern element has been marked visible (usually by collect linked aliases), then this is visible
592                return some(elem.name.elements, getBindingNameVisible);
593            }
594            else {
595                return resolver.isDeclarationVisible(elem);
596            }
597        }
598
599        function updateParamsList(node: Node, params: NodeArray<ParameterDeclaration>, modifierMask?: ModifierFlags) {
600            if (hasEffectiveModifier(node, ModifierFlags.Private)) {
601                return undefined!; // TODO: GH#18217
602            }
603            const newParams = map(params, p => ensureParameter(p, modifierMask));
604            if (!newParams) {
605                return undefined!; // TODO: GH#18217
606            }
607            return factory.createNodeArray(newParams, params.hasTrailingComma);
608        }
609
610        function updateAccessorParamsList(input: AccessorDeclaration, isPrivate: boolean) {
611            let newParams: ParameterDeclaration[] | undefined;
612            if (!isPrivate) {
613                const thisParameter = getThisParameter(input);
614                if (thisParameter) {
615                    newParams = [ensureParameter(thisParameter)];
616                }
617            }
618            if (isSetAccessorDeclaration(input)) {
619                let newValueParameter: ParameterDeclaration | undefined;
620                if (!isPrivate) {
621                    const valueParameter = getSetAccessorValueParameter(input);
622                    if (valueParameter) {
623                        const accessorType = getTypeAnnotationFromAllAccessorDeclarations(input, resolver.getAllAccessorDeclarations(input));
624                        newValueParameter = ensureParameter(valueParameter, /*modifierMask*/ undefined, accessorType);
625                    }
626                }
627                if (!newValueParameter) {
628                    newValueParameter = factory.createParameterDeclaration(
629                        /*decorators*/ undefined,
630                        /*modifiers*/ undefined,
631                        /*dotDotDotToken*/ undefined,
632                        "value"
633                    );
634                }
635                newParams = append(newParams, newValueParameter);
636            }
637            return factory.createNodeArray(newParams || emptyArray);
638        }
639
640        function ensureTypeParams(node: Node, params: NodeArray<TypeParameterDeclaration> | undefined) {
641            return hasEffectiveModifier(node, ModifierFlags.Private) ? undefined : visitNodes(params, visitDeclarationSubtree);
642        }
643
644        function isEnclosingDeclaration(node: Node) {
645            return isSourceFile(node)
646                || isTypeAliasDeclaration(node)
647                || isModuleDeclaration(node)
648                || isClassDeclaration(node)
649                || isStructDeclaration(node)
650                || isInterfaceDeclaration(node)
651                || isFunctionLike(node)
652                || isIndexSignatureDeclaration(node)
653                || isMappedTypeNode(node);
654        }
655
656        function checkEntityNameVisibility(entityName: EntityNameOrEntityNameExpression, enclosingDeclaration: Node) {
657            const visibilityResult = resolver.isEntityNameVisible(entityName, enclosingDeclaration);
658            handleSymbolAccessibilityError(visibilityResult);
659            recordTypeReferenceDirectivesIfNecessary(resolver.getTypeReferenceDirectivesForEntityName(entityName));
660        }
661
662        function preserveJsDoc<T extends Node>(updated: T, original: Node): T {
663            if (hasJSDocNodes(updated) && hasJSDocNodes(original)) {
664                updated.jsDoc = original.jsDoc;
665            }
666            return setCommentRange(updated, getCommentRange(original));
667        }
668
669        function rewriteModuleSpecifier<T extends Node>(parent: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration | ImportTypeNode, input: T | undefined): T | StringLiteral {
670            if (!input) return undefined!; // TODO: GH#18217
671            resultHasExternalModuleIndicator = resultHasExternalModuleIndicator || (parent.kind !== SyntaxKind.ModuleDeclaration && parent.kind !== SyntaxKind.ImportType);
672            if (isStringLiteralLike(input)) {
673                if (isBundledEmit) {
674                    const newName = getExternalModuleNameFromDeclaration(context.getEmitHost(), resolver, parent);
675                    if (newName) {
676                        return factory.createStringLiteral(newName);
677                    }
678                }
679                else {
680                    const symbol = resolver.getSymbolOfExternalModuleSpecifier(input);
681                    if (symbol) {
682                        (exportedModulesFromDeclarationEmit || (exportedModulesFromDeclarationEmit = [])).push(symbol);
683                    }
684                }
685            }
686            return input;
687        }
688
689        function transformImportEqualsDeclaration(decl: ImportEqualsDeclaration) {
690            if (!resolver.isDeclarationVisible(decl)) return;
691            if (decl.moduleReference.kind === SyntaxKind.ExternalModuleReference) {
692                // Rewrite external module names if necessary
693                const specifier = getExternalModuleImportEqualsDeclarationExpression(decl);
694                return factory.updateImportEqualsDeclaration(
695                    decl,
696                    /*decorators*/ undefined,
697                    decl.modifiers,
698                    decl.isTypeOnly,
699                    decl.name,
700                    factory.updateExternalModuleReference(decl.moduleReference, rewriteModuleSpecifier(decl, specifier))
701                );
702            }
703            else {
704                const oldDiag = getSymbolAccessibilityDiagnostic;
705                getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(decl);
706                checkEntityNameVisibility(decl.moduleReference, enclosingDeclaration);
707                getSymbolAccessibilityDiagnostic = oldDiag;
708                return decl;
709            }
710        }
711
712        function transformImportDeclaration(decl: ImportDeclaration) {
713            if (!decl.importClause) {
714                // import "mod" - possibly needed for side effects? (global interface patches, module augmentations, etc)
715                return factory.updateImportDeclaration(
716                    decl,
717                    /*decorators*/ undefined,
718                    decl.modifiers,
719                    decl.importClause,
720                    rewriteModuleSpecifier(decl, decl.moduleSpecifier)
721                );
722            }
723            // The `importClause` visibility corresponds to the default's visibility.
724            const visibleDefaultBinding = decl.importClause && decl.importClause.name && resolver.isDeclarationVisible(decl.importClause) ? decl.importClause.name : undefined;
725            if (!decl.importClause.namedBindings) {
726                // No named bindings (either namespace or list), meaning the import is just default or should be elided
727                return visibleDefaultBinding && factory.updateImportDeclaration(decl, /*decorators*/ undefined, decl.modifiers, factory.updateImportClause(
728                    decl.importClause,
729                    decl.importClause.isTypeOnly,
730                    visibleDefaultBinding,
731                    /*namedBindings*/ undefined,
732                ), rewriteModuleSpecifier(decl, decl.moduleSpecifier));
733            }
734            if (decl.importClause.namedBindings.kind === SyntaxKind.NamespaceImport) {
735                // Namespace import (optionally with visible default)
736                const namedBindings = resolver.isDeclarationVisible(decl.importClause.namedBindings) ? decl.importClause.namedBindings : /*namedBindings*/ undefined;
737                return visibleDefaultBinding || namedBindings ? factory.updateImportDeclaration(decl, /*decorators*/ undefined, decl.modifiers, factory.updateImportClause(
738                    decl.importClause,
739                    decl.importClause.isTypeOnly,
740                    visibleDefaultBinding,
741                    namedBindings,
742                ), rewriteModuleSpecifier(decl, decl.moduleSpecifier)) : undefined;
743            }
744            // Named imports (optionally with visible default)
745            const bindingList = mapDefined(decl.importClause.namedBindings.elements, b => resolver.isDeclarationVisible(b) ? b : undefined);
746            if ((bindingList && bindingList.length) || visibleDefaultBinding) {
747                return factory.updateImportDeclaration(
748                    decl,
749                    /*decorators*/ undefined,
750                    decl.modifiers,
751                    factory.updateImportClause(
752                        decl.importClause,
753                        decl.importClause.isTypeOnly,
754                        visibleDefaultBinding,
755                        bindingList && bindingList.length ? factory.updateNamedImports(decl.importClause.namedBindings, bindingList) : undefined,
756                    ),
757                    rewriteModuleSpecifier(decl, decl.moduleSpecifier)
758                );
759            }
760            // Augmentation of export depends on import
761            if (resolver.isImportRequiredByAugmentation(decl)) {
762                return factory.updateImportDeclaration(
763                    decl,
764                    /*decorators*/ undefined,
765                    decl.modifiers,
766                    /*importClause*/ undefined,
767                    rewriteModuleSpecifier(decl, decl.moduleSpecifier)
768                );
769            }
770            // Nothing visible
771        }
772
773        function transformAndReplaceLatePaintedStatements(statements: NodeArray<Statement>): NodeArray<Statement> {
774            // This is a `while` loop because `handleSymbolAccessibilityError` can see additional import aliases marked as visible during
775            // error handling which must now be included in the output and themselves checked for errors.
776            // For example:
777            // ```
778            // module A {
779            //   export module Q {}
780            //   import B = Q;
781            //   import C = B;
782            //   export import D = C;
783            // }
784            // ```
785            // 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
786            // 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
787            // dependent imports and allowing a valid declaration file output. Today, this dependent alias marking only happens for internal import aliases.
788            while (length(lateMarkedStatements)) {
789                const i = lateMarkedStatements!.shift()!;
790                if (!isLateVisibilityPaintedStatement(i)) {
791                    return Debug.fail(`Late replaced statement was found which is not handled by the declaration transformer!: ${(ts as any).SyntaxKind ? (ts as any).SyntaxKind[(i as any).kind] : (i as any).kind}`);
792                }
793                const priorNeedsDeclare = needsDeclare;
794                needsDeclare = i.parent && isSourceFile(i.parent) && !(isExternalModule(i.parent) && isBundledEmit);
795                const result = transformTopLevelDeclaration(i);
796                needsDeclare = priorNeedsDeclare;
797                lateStatementReplacementMap.set(getOriginalNodeId(i), result);
798            }
799
800            // And lastly, we need to get the final form of all those indetermine import declarations from before and add them to the output list
801            // (and remove them from the set to examine for outter declarations)
802            return visitNodes(statements, visitLateVisibilityMarkedStatements);
803
804            function visitLateVisibilityMarkedStatements(statement: Statement) {
805                if (isLateVisibilityPaintedStatement(statement)) {
806                    const key = getOriginalNodeId(statement);
807                    if (lateStatementReplacementMap.has(key)) {
808                        const result = lateStatementReplacementMap.get(key);
809                        lateStatementReplacementMap.delete(key);
810                        if (result) {
811                            if (isArray(result) ? some(result, needsScopeMarker) : needsScopeMarker(result)) {
812                                // Top-level declarations in .d.ts files are always considered exported even without a modifier unless there's an export assignment or specifier
813                                needsScopeFixMarker = true;
814                            }
815                            if (isSourceFile(statement.parent) && (isArray(result) ? some(result, isExternalModuleIndicator) : isExternalModuleIndicator(result))) {
816                                resultHasExternalModuleIndicator = true;
817                            }
818                        }
819                        return result;
820                    }
821                }
822                return statement;
823            }
824        }
825
826        function visitDeclarationSubtree(input: Node): VisitResult<Node> {
827            if (shouldStripInternal(input)) return;
828            if (isDeclaration(input)) {
829                if (isDeclarationAndNotVisible(input)) return;
830                if (hasDynamicName(input) && !resolver.isLateBound(getParseTreeNode(input) as Declaration)) {
831                    return;
832                }
833            }
834
835            // Elide implementation signatures from overload sets
836            if (isFunctionLike(input) && resolver.isImplementationOfOverload(input)) return;
837
838            // Elide semicolon class statements
839            if (isSemicolonClassElement(input)) return;
840
841            let previousEnclosingDeclaration: typeof enclosingDeclaration;
842            if (isEnclosingDeclaration(input)) {
843                previousEnclosingDeclaration = enclosingDeclaration;
844                enclosingDeclaration = input as Declaration;
845            }
846            const oldDiag = getSymbolAccessibilityDiagnostic;
847
848            // Setup diagnostic-related flags before first potential `cleanup` call, otherwise
849            // We'd see a TDZ violation at runtime
850            const canProduceDiagnostic = canProduceDiagnostics(input);
851            const oldWithinObjectLiteralType = suppressNewDiagnosticContexts;
852            let shouldEnterSuppressNewDiagnosticsContextContext = ((input.kind === SyntaxKind.TypeLiteral || input.kind === SyntaxKind.MappedType) && input.parent.kind !== SyntaxKind.TypeAliasDeclaration);
853
854            // Emit methods which are private as properties with no type information
855            if (isMethodDeclaration(input) || isMethodSignature(input)) {
856                if (hasEffectiveModifier(input, ModifierFlags.Private)) {
857                    if (input.symbol && input.symbol.declarations && input.symbol.declarations[0] !== input) return; // Elide all but the first overload
858                    return cleanup(factory.createPropertyDeclaration(/*decorators*/ undefined, ensureModifiers(input), input.name, /*questionToken*/ undefined, /*type*/ undefined, /*initializer*/ undefined));
859                }
860            }
861
862            if (canProduceDiagnostic && !suppressNewDiagnosticContexts) {
863                getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(input as DeclarationDiagnosticProducing);
864            }
865
866            if (isTypeQueryNode(input)) {
867                checkEntityNameVisibility(input.exprName, enclosingDeclaration);
868            }
869
870            if (shouldEnterSuppressNewDiagnosticsContextContext) {
871                // We stop making new diagnostic contexts within object literal types. Unless it's an object type on the RHS of a type alias declaration. Then we do.
872                suppressNewDiagnosticContexts = true;
873            }
874
875            if (isProcessedComponent(input)) {
876                switch (input.kind) {
877                    case SyntaxKind.ExpressionWithTypeArguments: {
878                        if ((isEntityName(input.expression) || isEntityNameExpression(input.expression))) {
879                            checkEntityNameVisibility(input.expression, enclosingDeclaration);
880                        }
881                        const node = visitEachChild(input, visitDeclarationSubtree, context);
882                        return cleanup(factory.updateExpressionWithTypeArguments(node, node.expression, node.typeArguments));
883                    }
884                    case SyntaxKind.TypeReference: {
885                        checkEntityNameVisibility(input.typeName, enclosingDeclaration);
886                        const node = visitEachChild(input, visitDeclarationSubtree, context);
887                        return cleanup(factory.updateTypeReferenceNode(node, node.typeName, node.typeArguments));
888                    }
889                    case SyntaxKind.ConstructSignature:
890                        return cleanup(factory.updateConstructSignature(
891                            input,
892                            ensureTypeParams(input, input.typeParameters),
893                            updateParamsList(input, input.parameters),
894                            ensureType(input, input.type)
895                        ));
896                    case SyntaxKind.Constructor: {
897                        // A constructor declaration may not have a type annotation
898                        const ctor = factory.createConstructorDeclaration(
899                            /*decorators*/ undefined,
900                            /*modifiers*/ ensureModifiers(input),
901                            updateParamsList(input, input.parameters, ModifierFlags.None),
902                            /*body*/ undefined
903                        );
904                        return cleanup(ctor);
905                    }
906                    case SyntaxKind.MethodDeclaration: {
907                        if (isPrivateIdentifier(input.name)) {
908                            return cleanup(/*returnValue*/ undefined);
909                        }
910                        let reservedDecorators;
911                        if (input.parent.kind === SyntaxKind.StructDeclaration) {
912                            reservedDecorators = ensureEtsDecorators(input);
913                        }
914                        const sig = factory.createMethodDeclaration(
915                            reservedDecorators,
916                            ensureModifiers(input),
917                            /*asteriskToken*/ undefined,
918                            input.name,
919                            input.questionToken,
920                            inEtsStylesContext(input) ? undefined : ensureTypeParams(input, input.typeParameters),
921                            updateParamsList(input, input.parameters),
922                            ensureType(input, input.type),
923                            /*body*/ undefined
924                        );
925                        return cleanup(sig);
926                    }
927                    case SyntaxKind.GetAccessor: {
928                        if (isPrivateIdentifier(input.name)) {
929                            return cleanup(/*returnValue*/ undefined);
930                        }
931                        const accessorType = getTypeAnnotationFromAllAccessorDeclarations(input, resolver.getAllAccessorDeclarations(input));
932                        return cleanup(factory.updateGetAccessorDeclaration(
933                            input,
934                            /*decorators*/ undefined,
935                            ensureModifiers(input),
936                            input.name,
937                            updateAccessorParamsList(input, hasEffectiveModifier(input, ModifierFlags.Private)),
938                            ensureType(input, accessorType),
939                            /*body*/ undefined));
940                    }
941                    case SyntaxKind.SetAccessor: {
942                        if (isPrivateIdentifier(input.name)) {
943                            return cleanup(/*returnValue*/ undefined);
944                        }
945                        return cleanup(factory.updateSetAccessorDeclaration(
946                            input,
947                            /*decorators*/ undefined,
948                            ensureModifiers(input),
949                            input.name,
950                            updateAccessorParamsList(input, hasEffectiveModifier(input, ModifierFlags.Private)),
951                            /*body*/ undefined));
952                    }
953                    case SyntaxKind.PropertyDeclaration:
954                        if (isPrivateIdentifier(input.name)) {
955                            return cleanup(/*returnValue*/ undefined);
956                        }
957                        return cleanup(factory.updatePropertyDeclaration(
958                            input,
959                            input.parent.kind === SyntaxKind.StructDeclaration ? ensureEtsDecorators(input) : undefined,
960                            ensureModifiers(input),
961                            input.name,
962                            input.questionToken,
963                            ensureType(input, input.type),
964                            ensureNoInitializer(input)
965                        ));
966                    case SyntaxKind.PropertySignature:
967                        if (isPrivateIdentifier(input.name)) {
968                            return cleanup(/*returnValue*/ undefined);
969                        }
970                        return cleanup(factory.updatePropertySignature(
971                            input,
972                            ensureModifiers(input),
973                            input.name,
974                            input.questionToken,
975                            ensureType(input, input.type)
976                        ));
977                    case SyntaxKind.MethodSignature: {
978                        if (isPrivateIdentifier(input.name)) {
979                            return cleanup(/*returnValue*/ undefined);
980                        }
981                        return cleanup(factory.updateMethodSignature(
982                            input,
983                            ensureModifiers(input),
984                            input.name,
985                            input.questionToken,
986                            ensureTypeParams(input, input.typeParameters),
987                            updateParamsList(input, input.parameters),
988                            ensureType(input, input.type)
989                        ));
990                    }
991                    case SyntaxKind.CallSignature: {
992                        return cleanup(factory.updateCallSignature(
993                            input,
994                            ensureTypeParams(input, input.typeParameters),
995                            updateParamsList(input, input.parameters),
996                            ensureType(input, input.type)
997                        ));
998                    }
999                    case SyntaxKind.IndexSignature: {
1000                        return cleanup(factory.updateIndexSignature(
1001                            input,
1002                            /*decorators*/ undefined,
1003                            ensureModifiers(input),
1004                            updateParamsList(input, input.parameters),
1005                            visitNode(input.type, visitDeclarationSubtree) || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword)
1006                        ));
1007                    }
1008                    case SyntaxKind.VariableDeclaration: {
1009                        if (isBindingPattern(input.name)) {
1010                            return recreateBindingPattern(input.name);
1011                        }
1012                        shouldEnterSuppressNewDiagnosticsContextContext = true;
1013                        suppressNewDiagnosticContexts = true; // Variable declaration types also suppress new diagnostic contexts, provided the contexts wouldn't be made for binding pattern types
1014                        return cleanup(factory.updateVariableDeclaration(input, input.name, /*exclamationToken*/ undefined, ensureType(input, input.type), ensureNoInitializer(input)));
1015                    }
1016                    case SyntaxKind.TypeParameter: {
1017                        if (isPrivateMethodTypeParameter(input) && (input.default || input.constraint)) {
1018                            return cleanup(factory.updateTypeParameterDeclaration(input, input.name, /*constraint*/ undefined, /*defaultType*/ undefined));
1019                        }
1020                        return cleanup(visitEachChild(input, visitDeclarationSubtree, context));
1021                    }
1022                    case SyntaxKind.ConditionalType: {
1023                        // We have to process conditional types in a special way because for visibility purposes we need to push a new enclosingDeclaration
1024                        // just for the `infer` types in the true branch. It's an implicit declaration scope that only applies to _part_ of the type.
1025                        const checkType = visitNode(input.checkType, visitDeclarationSubtree);
1026                        const extendsType = visitNode(input.extendsType, visitDeclarationSubtree);
1027                        const oldEnclosingDecl = enclosingDeclaration;
1028                        enclosingDeclaration = input.trueType;
1029                        const trueType = visitNode(input.trueType, visitDeclarationSubtree);
1030                        enclosingDeclaration = oldEnclosingDecl;
1031                        const falseType = visitNode(input.falseType, visitDeclarationSubtree);
1032                        return cleanup(factory.updateConditionalTypeNode(input, checkType, extendsType, trueType, falseType));
1033                    }
1034                    case SyntaxKind.FunctionType: {
1035                        return cleanup(factory.updateFunctionTypeNode(input, visitNodes(input.typeParameters, visitDeclarationSubtree), updateParamsList(input, input.parameters), visitNode(input.type, visitDeclarationSubtree)));
1036                    }
1037                    case SyntaxKind.ConstructorType: {
1038                        return cleanup(factory.updateConstructorTypeNode(input, ensureModifiers(input), visitNodes(input.typeParameters, visitDeclarationSubtree), updateParamsList(input, input.parameters), visitNode(input.type, visitDeclarationSubtree)));
1039                    }
1040                    case SyntaxKind.ImportType: {
1041                        if (!isLiteralImportTypeNode(input)) return cleanup(input);
1042                        return cleanup(factory.updateImportTypeNode(
1043                            input,
1044                            factory.updateLiteralTypeNode(input.argument, rewriteModuleSpecifier(input, input.argument.literal)),
1045                            input.qualifier,
1046                            visitNodes(input.typeArguments, visitDeclarationSubtree, isTypeNode),
1047                            input.isTypeOf
1048                        ));
1049                    }
1050                    default: Debug.assertNever(input, `Attempted to process unhandled node kind: ${(ts as any).SyntaxKind[(input as any).kind]}`);
1051                }
1052            }
1053
1054            if (isTupleTypeNode(input) && (getLineAndCharacterOfPosition(currentSourceFile, input.pos).line === getLineAndCharacterOfPosition(currentSourceFile, input.end).line)) {
1055                setEmitFlags(input, EmitFlags.SingleLine);
1056            }
1057
1058            return cleanup(visitEachChild(input, visitDeclarationSubtree, context));
1059
1060            function cleanup<T extends Node>(returnValue: T | undefined): T | undefined {
1061                if (returnValue && canProduceDiagnostic && hasDynamicName(input as Declaration)) {
1062                    checkName(input as DeclarationDiagnosticProducing);
1063                }
1064                if (isEnclosingDeclaration(input)) {
1065                    enclosingDeclaration = previousEnclosingDeclaration;
1066                }
1067                if (canProduceDiagnostic && !suppressNewDiagnosticContexts) {
1068                    getSymbolAccessibilityDiagnostic = oldDiag;
1069                }
1070                if (shouldEnterSuppressNewDiagnosticsContextContext) {
1071                    suppressNewDiagnosticContexts = oldWithinObjectLiteralType;
1072                }
1073                if (returnValue === input) {
1074                    return returnValue;
1075                }
1076                return returnValue && setOriginalNode(preserveJsDoc(returnValue, input), input);
1077            }
1078        }
1079
1080        function inEtsStylesContext(input: LateVisibilityPaintedStatement | MethodDeclaration) {
1081            if (!host.getCompilerOptions().ets?.styles.component || getSourceFileOfNode(input).scriptKind !== ScriptKind.ETS) {
1082                return false;
1083            }
1084            const decorators = input.decorators;
1085            if (decorators === undefined) {
1086                return false;
1087            }
1088            for (const decorator of decorators) {
1089                if (isIdentifier(decorator.expression) && decorator.expression.escapedText.toString() === "Styles") {
1090                    return true;
1091                }
1092            }
1093            return false;
1094        }
1095
1096        function isPrivateMethodTypeParameter(node: TypeParameterDeclaration) {
1097            return node.parent.kind === SyntaxKind.MethodDeclaration && hasEffectiveModifier(node.parent, ModifierFlags.Private);
1098        }
1099
1100        function visitDeclarationStatements(input: Node): VisitResult<Node> {
1101            if (!isPreservedDeclarationStatement(input)) {
1102                // return undefined for unmatched kinds to omit them from the tree
1103                return;
1104            }
1105            if (shouldStripInternal(input)) return;
1106
1107            switch (input.kind) {
1108                case SyntaxKind.ExportDeclaration: {
1109                    if (isSourceFile(input.parent)) {
1110                        resultHasExternalModuleIndicator = true;
1111                    }
1112                    resultHasScopeMarker = true;
1113                    // Always visible if the parent node isn't dropped for being not visible
1114                    // Rewrite external module names if necessary
1115                    return factory.updateExportDeclaration(
1116                        input,
1117                        /*decorators*/ undefined,
1118                        input.modifiers,
1119                        input.isTypeOnly,
1120                        input.exportClause,
1121                        rewriteModuleSpecifier(input, input.moduleSpecifier),
1122                    );
1123                }
1124                case SyntaxKind.ExportAssignment: {
1125                    // Always visible if the parent node isn't dropped for being not visible
1126                    if (isSourceFile(input.parent)) {
1127                        resultHasExternalModuleIndicator = true;
1128                    }
1129                    resultHasScopeMarker = true;
1130                    if (input.expression.kind === SyntaxKind.Identifier) {
1131                        return input;
1132                    }
1133                    else {
1134                        const newId = factory.createUniqueName("_default", GeneratedIdentifierFlags.Optimistic);
1135                        getSymbolAccessibilityDiagnostic = () => ({
1136                            diagnosticMessage: Diagnostics.Default_export_of_the_module_has_or_is_using_private_name_0,
1137                            errorNode: input
1138                        });
1139                        errorFallbackNode = input;
1140                        const varDecl = factory.createVariableDeclaration(newId, /*exclamationToken*/ undefined, resolver.createTypeOfExpression(input.expression, input, declarationEmitNodeBuilderFlags, symbolTracker), /*initializer*/ undefined);
1141                        errorFallbackNode = undefined;
1142                        const statement = factory.createVariableStatement(needsDeclare ? [factory.createModifier(SyntaxKind.DeclareKeyword)] : [], factory.createVariableDeclarationList([varDecl], NodeFlags.Const));
1143                        return [statement, factory.updateExportAssignment(input, input.decorators, input.modifiers, newId)];
1144                    }
1145                }
1146            }
1147
1148            const result = transformTopLevelDeclaration(input);
1149            // Don't actually transform yet; just leave as original node - will be elided/swapped by late pass
1150            lateStatementReplacementMap.set(getOriginalNodeId(input), result);
1151            return input;
1152        }
1153
1154        function stripExportModifiers(statement: Statement): Statement {
1155            if (isImportEqualsDeclaration(statement) || hasEffectiveModifier(statement, ModifierFlags.Default) || !canHaveModifiers(statement)) {
1156                // `export import` statements should remain as-is, as imports are _not_ implicitly exported in an ambient namespace
1157                // Likewise, `export default` classes and the like and just be `default`, so we preserve their `export` modifiers, too
1158                return statement;
1159            }
1160
1161            const modifiers = factory.createModifiersFromModifierFlags(getEffectiveModifierFlags(statement) & (ModifierFlags.All ^ ModifierFlags.Export));
1162            return factory.updateModifiers(statement, modifiers);
1163        }
1164
1165        function transformTopLevelDeclaration(input: LateVisibilityPaintedStatement) {
1166            if (shouldStripInternal(input)) return;
1167            switch (input.kind) {
1168                case SyntaxKind.ImportEqualsDeclaration: {
1169                    return transformImportEqualsDeclaration(input);
1170                }
1171                case SyntaxKind.ImportDeclaration: {
1172                    return transformImportDeclaration(input);
1173                }
1174            }
1175            if (isDeclaration(input) && isDeclarationAndNotVisible(input)) return;
1176
1177            // Elide implementation signatures from overload sets
1178            if (isFunctionLike(input) && resolver.isImplementationOfOverload(input)) return;
1179
1180            let previousEnclosingDeclaration: typeof enclosingDeclaration;
1181            if (isEnclosingDeclaration(input)) {
1182                previousEnclosingDeclaration = enclosingDeclaration;
1183                enclosingDeclaration = input as Declaration;
1184            }
1185
1186            const canProdiceDiagnostic = canProduceDiagnostics(input);
1187            const oldDiag = getSymbolAccessibilityDiagnostic;
1188            if (canProdiceDiagnostic) {
1189                getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(input as DeclarationDiagnosticProducing);
1190            }
1191
1192            const previousNeedsDeclare = needsDeclare;
1193            switch (input.kind) {
1194                case SyntaxKind.TypeAliasDeclaration: // Type aliases get `declare`d if need be (for legacy support), but that's all
1195                    return cleanup(factory.updateTypeAliasDeclaration(
1196                        input,
1197                        /*decorators*/ undefined,
1198                        ensureModifiers(input),
1199                        input.name,
1200                        visitNodes(input.typeParameters, visitDeclarationSubtree, isTypeParameterDeclaration),
1201                        visitNode(input.type, visitDeclarationSubtree, isTypeNode)
1202                    ));
1203                case SyntaxKind.InterfaceDeclaration: {
1204                    return cleanup(factory.updateInterfaceDeclaration(
1205                        input,
1206                        /*decorators*/ undefined,
1207                        ensureModifiers(input),
1208                        input.name,
1209                        ensureTypeParams(input, input.typeParameters),
1210                        transformHeritageClauses(input.heritageClauses),
1211                        visitNodes(input.members, visitDeclarationSubtree)
1212                    ));
1213                }
1214                case SyntaxKind.FunctionDeclaration: {
1215                    // Generators lose their generator-ness, excepting their return type
1216                    const clean = cleanup(factory.updateFunctionDeclaration(
1217                        input,
1218                        getSourceFileOfNode(input).scriptKind === ScriptKind.ETS ? ensureEtsDecorators(input) : undefined,
1219                        ensureModifiers(input),
1220                        /*asteriskToken*/ undefined,
1221                        input.name,
1222                        inEtsStylesContext(input) ? undefined : ensureTypeParams(input, input.typeParameters),
1223                        updateParamsList(input, input.parameters),
1224                        ensureType(input, input.type),
1225                        /*body*/ undefined
1226                    ));
1227                    if (clean && resolver.isExpandoFunctionDeclaration(input)) {
1228                        const props = resolver.getPropertiesOfContainerFunction(input);
1229                        // Use parseNodeFactory so it is usable as an enclosing declaration
1230                        const fakespace = parseNodeFactory.createModuleDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, clean.name || factory.createIdentifier("_default"), factory.createModuleBlock([]), NodeFlags.Namespace);
1231                        setParent(fakespace, enclosingDeclaration as SourceFile | NamespaceDeclaration);
1232                        fakespace.locals = createSymbolTable(props);
1233                        fakespace.symbol = props[0].parent!;
1234                        const exportMappings: [Identifier, string][] = [];
1235                        let declarations: (VariableStatement | ExportDeclaration)[] = mapDefined(props, p => {
1236                            if (!isPropertyAccessExpression(p.valueDeclaration)) {
1237                                return undefined; // TODO GH#33569: Handle element access expressions that created late bound names (rather than silently omitting them)
1238                            }
1239                            getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(p.valueDeclaration);
1240                            const type = resolver.createTypeOfDeclaration(p.valueDeclaration, fakespace, declarationEmitNodeBuilderFlags, symbolTracker);
1241                            getSymbolAccessibilityDiagnostic = oldDiag;
1242                            const nameStr = unescapeLeadingUnderscores(p.escapedName);
1243                            const isNonContextualKeywordName = isStringANonContextualKeyword(nameStr);
1244                            const name = isNonContextualKeywordName ? factory.getGeneratedNameForNode(p.valueDeclaration) : factory.createIdentifier(nameStr);
1245                            if (isNonContextualKeywordName) {
1246                                exportMappings.push([name, nameStr]);
1247                            }
1248                            const varDecl = factory.createVariableDeclaration(name, /*exclamationToken*/ undefined, type, /*initializer*/ undefined);
1249                            return factory.createVariableStatement(isNonContextualKeywordName ? undefined : [factory.createToken(SyntaxKind.ExportKeyword)], factory.createVariableDeclarationList([varDecl]));
1250                        });
1251                        if (!exportMappings.length) {
1252                            declarations = mapDefined(declarations, declaration => factory.updateModifiers(declaration, ModifierFlags.None));
1253                        }
1254                        else {
1255                            declarations.push(factory.createExportDeclaration(
1256                                /*decorators*/ undefined,
1257                                /*modifiers*/ undefined,
1258                                /*isTypeOnly*/ false,
1259                                factory.createNamedExports(map(exportMappings, ([gen, exp]) => {
1260                                    return factory.createExportSpecifier(gen, exp);
1261                                }))
1262                            ));
1263                        }
1264                        const namespaceDecl = factory.createModuleDeclaration(/*decorators*/ undefined, ensureModifiers(input), input.name!, factory.createModuleBlock(declarations), NodeFlags.Namespace);
1265                        if (!hasEffectiveModifier(clean, ModifierFlags.Default)) {
1266                            return [clean, namespaceDecl];
1267                        }
1268
1269                        const modifiers = factory.createModifiersFromModifierFlags((getEffectiveModifierFlags(clean) & ~ModifierFlags.ExportDefault) | ModifierFlags.Ambient);
1270                        const cleanDeclaration = factory.updateFunctionDeclaration(
1271                            clean,
1272                            clean.decorators,
1273                            modifiers,
1274                            /*asteriskToken*/ undefined,
1275                            clean.name,
1276                            clean.typeParameters,
1277                            clean.parameters,
1278                            clean.type,
1279                            /*body*/ undefined
1280                        );
1281
1282                        const namespaceDeclaration = factory.updateModuleDeclaration(
1283                            namespaceDecl,
1284                            /*decorators*/ undefined,
1285                            modifiers,
1286                            namespaceDecl.name,
1287                            namespaceDecl.body
1288                        );
1289
1290                        const exportDefaultDeclaration = factory.createExportAssignment(
1291                            /*decorators*/ undefined,
1292                            /*modifiers*/ undefined,
1293                            /*isExportEquals*/ false,
1294                            namespaceDecl.name
1295                        );
1296
1297                        if (isSourceFile(input.parent)) {
1298                            resultHasExternalModuleIndicator = true;
1299                        }
1300                        resultHasScopeMarker = true;
1301
1302                        return [cleanDeclaration, namespaceDeclaration, exportDefaultDeclaration];
1303                    }
1304                    else {
1305                        return clean;
1306                    }
1307                }
1308                case SyntaxKind.ModuleDeclaration: {
1309                    needsDeclare = false;
1310                    const inner = input.body;
1311                    if (inner && inner.kind === SyntaxKind.ModuleBlock) {
1312                        const oldNeedsScopeFix = needsScopeFixMarker;
1313                        const oldHasScopeFix = resultHasScopeMarker;
1314                        resultHasScopeMarker = false;
1315                        needsScopeFixMarker = false;
1316                        const statements = visitNodes(inner.statements, visitDeclarationStatements);
1317                        let lateStatements = transformAndReplaceLatePaintedStatements(statements);
1318                        if (input.flags & NodeFlags.Ambient) {
1319                            needsScopeFixMarker = false; // If it was `declare`'d everything is implicitly exported already, ignore late printed "privates"
1320                        }
1321                        // With the final list of statements, there are 3 possibilities:
1322                        // 1. There's an export assignment or export declaration in the namespace - do nothing
1323                        // 2. Everything is exported and there are no export assignments or export declarations - strip all export modifiers
1324                        // 3. Some things are exported, some are not, and there's no marker - add an empty marker
1325                        if (!isGlobalScopeAugmentation(input) && !hasScopeMarker(lateStatements) && !resultHasScopeMarker) {
1326                            if (needsScopeFixMarker) {
1327                                lateStatements = factory.createNodeArray([...lateStatements, createEmptyExports(factory)]);
1328                            }
1329                            else {
1330                                lateStatements = visitNodes(lateStatements, stripExportModifiers);
1331                            }
1332                        }
1333                        const body = factory.updateModuleBlock(inner, lateStatements);
1334                        needsDeclare = previousNeedsDeclare;
1335                        needsScopeFixMarker = oldNeedsScopeFix;
1336                        resultHasScopeMarker = oldHasScopeFix;
1337                        const mods = ensureModifiers(input);
1338                        return cleanup(factory.updateModuleDeclaration(
1339                            input,
1340                            /*decorators*/ undefined,
1341                            mods,
1342                            isExternalModuleAugmentation(input) ? rewriteModuleSpecifier(input, input.name) : input.name,
1343                            body
1344                        ));
1345                    }
1346                    else {
1347                        needsDeclare = previousNeedsDeclare;
1348                        const mods = ensureModifiers(input);
1349                        needsDeclare = false;
1350                        visitNode(inner, visitDeclarationStatements);
1351                        // eagerly transform nested namespaces (the nesting doesn't need any elision or painting done)
1352                        const id = getOriginalNodeId(inner!); // TODO: GH#18217
1353                        const body = lateStatementReplacementMap.get(id);
1354                        lateStatementReplacementMap.delete(id);
1355                        return cleanup(factory.updateModuleDeclaration(
1356                            input,
1357                            /*decorators*/ undefined,
1358                            mods,
1359                            input.name,
1360                            body as ModuleBody
1361                        ));
1362                    }
1363                }
1364                case SyntaxKind.StructDeclaration: {
1365                    errorNameNode = input.name;
1366                    errorFallbackNode = input;
1367
1368                    const decorators = ensureEtsDecorators(input);
1369                    const modifiers = factory.createNodeArray(ensureModifiers(input));
1370                    const typeParameters = ensureTypeParams(input, input.typeParameters);
1371                    // eslint-disable-next-line boolean-trivia
1372                    const memberNodes = visitNodes(input.members, visitDeclarationSubtree, undefined, 1);
1373                    const members = factory.createNodeArray(memberNodes);
1374
1375                    return cleanup(factory.updateStructDeclaration(
1376                        input,
1377                        decorators,
1378                        modifiers,
1379                        input.name,
1380                        typeParameters,
1381                        /*heritageClauses*/ undefined,
1382                        members
1383                    ));
1384                }
1385                case SyntaxKind.ClassDeclaration: {
1386                    errorNameNode = input.name;
1387                    errorFallbackNode = input;
1388                    const modifiers = factory.createNodeArray(ensureModifiers(input));
1389                    const typeParameters = ensureTypeParams(input, input.typeParameters);
1390                    const ctor = getFirstConstructorWithBody(input);
1391                    let parameterProperties: readonly PropertyDeclaration[] | undefined;
1392                    if (ctor) {
1393                        const oldDiag = getSymbolAccessibilityDiagnostic;
1394                        parameterProperties = compact(flatMap(ctor.parameters, (param) => {
1395                            if (!hasSyntacticModifier(param, ModifierFlags.ParameterPropertyModifier) || shouldStripInternal(param)) return;
1396                            getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(param);
1397                            if (param.name.kind === SyntaxKind.Identifier) {
1398                                return preserveJsDoc(factory.createPropertyDeclaration(
1399                                    /*decorators*/ undefined,
1400                                    ensureModifiers(param),
1401                                    param.name,
1402                                    param.questionToken,
1403                                    ensureType(param, param.type),
1404                                    ensureNoInitializer(param)), param);
1405                            }
1406                            else {
1407                                // Pattern - this is currently an error, but we emit declarations for it somewhat correctly
1408                                return walkBindingPattern(param.name);
1409                            }
1410
1411                            function walkBindingPattern(pattern: BindingPattern) {
1412                                let elems: PropertyDeclaration[] | undefined;
1413                                for (const elem of pattern.elements) {
1414                                    if (isOmittedExpression(elem)) continue;
1415                                    if (isBindingPattern(elem.name)) {
1416                                        elems = concatenate(elems, walkBindingPattern(elem.name));
1417                                    }
1418                                    elems = elems || [];
1419                                    elems.push(factory.createPropertyDeclaration(
1420                                        /*decorators*/ undefined,
1421                                        ensureModifiers(param),
1422                                        elem.name as Identifier,
1423                                        /*questionToken*/ undefined,
1424                                        ensureType(elem, /*type*/ undefined),
1425                                        /*initializer*/ undefined
1426                                    ));
1427                                }
1428                                return elems;
1429                            }
1430                        }));
1431                        getSymbolAccessibilityDiagnostic = oldDiag;
1432                    }
1433
1434                    const hasPrivateIdentifier = some(input.members, member => !!member.name && isPrivateIdentifier(member.name));
1435                    // When the class has at least one private identifier, create a unique constant identifier to retain the nominal typing behavior
1436                    // Prevents other classes with the same public members from being used in place of the current class
1437                    const privateIdentifier = hasPrivateIdentifier ? [
1438                        factory.createPropertyDeclaration(
1439                            /*decorators*/ undefined,
1440                            /*modifiers*/ undefined,
1441                            factory.createPrivateIdentifier("#private"),
1442                            /*questionToken*/ undefined,
1443                            /*type*/ undefined,
1444                            /*initializer*/ undefined
1445                        )
1446                    ] : undefined;
1447                    const memberNodes = concatenate(concatenate(privateIdentifier, parameterProperties), visitNodes(input.members, visitDeclarationSubtree));
1448                    const members = factory.createNodeArray(memberNodes);
1449
1450                    const extendsClause = getEffectiveBaseTypeNode(input);
1451                    if (extendsClause && !isEntityNameExpression(extendsClause.expression) && extendsClause.expression.kind !== SyntaxKind.NullKeyword) {
1452                        // We must add a temporary declaration for the extends clause expression
1453
1454                        const oldId = input.name ? unescapeLeadingUnderscores(input.name.escapedText) : "default";
1455                        const newId = factory.createUniqueName(`${oldId}_base`, GeneratedIdentifierFlags.Optimistic);
1456                        getSymbolAccessibilityDiagnostic = () => ({
1457                            diagnosticMessage: Diagnostics.extends_clause_of_exported_class_0_has_or_is_using_private_name_1,
1458                            errorNode: extendsClause,
1459                            typeName: input.name
1460                        });
1461                        const varDecl = factory.createVariableDeclaration(newId, /*exclamationToken*/ undefined, resolver.createTypeOfExpression(extendsClause.expression, input, declarationEmitNodeBuilderFlags, symbolTracker), /*initializer*/ undefined);
1462                        const statement = factory.createVariableStatement(needsDeclare ? [factory.createModifier(SyntaxKind.DeclareKeyword)] : [], factory.createVariableDeclarationList([varDecl], NodeFlags.Const));
1463                        const heritageClauses = factory.createNodeArray(map(input.heritageClauses, clause => {
1464                            if (clause.token === SyntaxKind.ExtendsKeyword) {
1465                                const oldDiag = getSymbolAccessibilityDiagnostic;
1466                                getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(clause.types[0]);
1467                                const newClause = factory.updateHeritageClause(clause, map(clause.types, t => factory.updateExpressionWithTypeArguments(t, newId, visitNodes(t.typeArguments, visitDeclarationSubtree))));
1468                                getSymbolAccessibilityDiagnostic = oldDiag;
1469                                return newClause;
1470                            }
1471                            return factory.updateHeritageClause(clause, visitNodes(factory.createNodeArray(filter(clause.types, t => isEntityNameExpression(t.expression) || t.expression.kind === SyntaxKind.NullKeyword)), visitDeclarationSubtree));
1472                        }));
1473                        return [statement, cleanup(factory.updateClassDeclaration(
1474                            input,
1475                            getSourceFileOfNode(input).scriptKind === ScriptKind.ETS ? ensureEtsDecorators(input) : undefined,
1476                            modifiers,
1477                            input.name,
1478                            typeParameters,
1479                            heritageClauses,
1480                            members
1481                        ))!]; // TODO: GH#18217
1482                    }
1483                    else {
1484                        const heritageClauses = transformHeritageClauses(input.heritageClauses);
1485                        return cleanup(factory.updateClassDeclaration(
1486                            input,
1487                            getSourceFileOfNode(input).scriptKind === ScriptKind.ETS ? ensureEtsDecorators(input) : undefined,
1488                            modifiers,
1489                            input.name,
1490                            typeParameters,
1491                            heritageClauses,
1492                            members
1493                        ));
1494                    }
1495                }
1496                case SyntaxKind.VariableStatement: {
1497                    return cleanup(transformVariableStatement(input));
1498                }
1499                case SyntaxKind.EnumDeclaration: {
1500                    return cleanup(factory.updateEnumDeclaration(input, /*decorators*/ undefined, factory.createNodeArray(ensureModifiers(input)), input.name, factory.createNodeArray(mapDefined(input.members, m => {
1501                        if (shouldStripInternal(m)) return;
1502                        // Rewrite enum values to their constants, if available
1503                        const constValue = resolver.getConstantValue(m);
1504                        return preserveJsDoc(factory.updateEnumMember(m, m.name, constValue !== undefined ? typeof constValue === "string" ? factory.createStringLiteral(constValue) : factory.createNumericLiteral(constValue) : undefined), m);
1505                    }))));
1506                }
1507            }
1508            // Anything left unhandled is an error, so this should be unreachable
1509            return Debug.assertNever(input, `Unhandled top-level node in declaration emit: ${(ts as any).SyntaxKind[(input as any).kind]}`);
1510
1511            function cleanup<T extends Node>(node: T | undefined): T | undefined {
1512                if (isEnclosingDeclaration(input)) {
1513                    enclosingDeclaration = previousEnclosingDeclaration;
1514                }
1515                if (canProdiceDiagnostic) {
1516                    getSymbolAccessibilityDiagnostic = oldDiag;
1517                }
1518                if (input.kind === SyntaxKind.ModuleDeclaration) {
1519                    needsDeclare = previousNeedsDeclare;
1520                }
1521                if (node as Node === input) {
1522                    return node;
1523                }
1524                errorFallbackNode = undefined;
1525                errorNameNode = undefined;
1526                return node && setOriginalNode(preserveJsDoc(node, input), input);
1527            }
1528        }
1529
1530        function transformVariableStatement(input: VariableStatement) {
1531            if (!forEach(input.declarationList.declarations, getBindingNameVisible)) return;
1532            const nodes = visitNodes(input.declarationList.declarations, visitDeclarationSubtree);
1533            if (!length(nodes)) return;
1534            return factory.updateVariableStatement(input, factory.createNodeArray(ensureModifiers(input)), factory.updateVariableDeclarationList(input.declarationList, nodes));
1535        }
1536
1537        function recreateBindingPattern(d: BindingPattern): VariableDeclaration[] {
1538            return flatten<VariableDeclaration>(mapDefined(d.elements, e => recreateBindingElement(e)));
1539        }
1540
1541        function recreateBindingElement(e: ArrayBindingElement) {
1542            if (e.kind === SyntaxKind.OmittedExpression) {
1543                return;
1544            }
1545            if (e.name) {
1546                if (!getBindingNameVisible(e)) return;
1547                if (isBindingPattern(e.name)) {
1548                    return recreateBindingPattern(e.name);
1549                }
1550                else {
1551                    return factory.createVariableDeclaration(e.name, /*exclamationToken*/ undefined, ensureType(e, /*type*/ undefined), /*initializer*/ undefined);
1552                }
1553            }
1554        }
1555
1556        function checkName(node: DeclarationDiagnosticProducing) {
1557            let oldDiag: typeof getSymbolAccessibilityDiagnostic | undefined;
1558            if (!suppressNewDiagnosticContexts) {
1559                oldDiag = getSymbolAccessibilityDiagnostic;
1560                getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNodeName(node);
1561            }
1562            errorNameNode = (node as NamedDeclaration).name;
1563            Debug.assert(resolver.isLateBound(getParseTreeNode(node) as Declaration)); // Should only be called with dynamic names
1564            const decl = node as NamedDeclaration as LateBoundDeclaration;
1565            const entityName = decl.name.expression;
1566            checkEntityNameVisibility(entityName, enclosingDeclaration);
1567            if (!suppressNewDiagnosticContexts) {
1568                getSymbolAccessibilityDiagnostic = oldDiag!;
1569            }
1570            errorNameNode = undefined;
1571        }
1572
1573        function shouldStripInternal(node: Node) {
1574            return !!stripInternal && !!node && isInternalDeclaration(node, currentSourceFile);
1575        }
1576
1577        function isScopeMarker(node: Node) {
1578            return isExportAssignment(node) || isExportDeclaration(node);
1579        }
1580
1581        function hasScopeMarker(statements: readonly Statement[]) {
1582            return some(statements, isScopeMarker);
1583        }
1584
1585        function ensureModifiers(node: Node): readonly Modifier[] | undefined {
1586            const currentFlags = getEffectiveModifierFlags(node);
1587            const newFlags = ensureModifierFlags(node);
1588            if (currentFlags === newFlags) {
1589                return node.modifiers;
1590            }
1591            return factory.createModifiersFromModifierFlags(newFlags);
1592        }
1593
1594        function ensureEtsDecorators(node: Node): NodeArray<Decorator> | undefined {
1595            if (node.decorators) {
1596                return factory.createNodeArray(getEffectiveDecorators(node.decorators, host));
1597            }
1598            return undefined;
1599        }
1600
1601        function ensureModifierFlags(node: Node): ModifierFlags {
1602            let mask = ModifierFlags.All ^ (ModifierFlags.Public | ModifierFlags.Async); // No async modifiers in declaration files
1603            let additions = (needsDeclare && !isAlwaysType(node)) ? ModifierFlags.Ambient : ModifierFlags.None;
1604            const parentIsFile = node.parent.kind === SyntaxKind.SourceFile;
1605            if (!parentIsFile || (isBundledEmit && parentIsFile && isExternalModule(node.parent as SourceFile))) {
1606                mask ^= ModifierFlags.Ambient;
1607                additions = ModifierFlags.None;
1608            }
1609            return maskModifierFlags(node, mask, additions);
1610        }
1611
1612        function getTypeAnnotationFromAllAccessorDeclarations(node: AccessorDeclaration, accessors: AllAccessorDeclarations) {
1613            let accessorType = getTypeAnnotationFromAccessor(node);
1614            if (!accessorType && node !== accessors.firstAccessor) {
1615                accessorType = getTypeAnnotationFromAccessor(accessors.firstAccessor);
1616                // If we end up pulling the type from the second accessor, we also need to change the diagnostic context to get the expected error message
1617                getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(accessors.firstAccessor);
1618            }
1619            if (!accessorType && accessors.secondAccessor && node !== accessors.secondAccessor) {
1620                accessorType = getTypeAnnotationFromAccessor(accessors.secondAccessor);
1621                // If we end up pulling the type from the second accessor, we also need to change the diagnostic context to get the expected error message
1622                getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(accessors.secondAccessor);
1623            }
1624            return accessorType;
1625        }
1626
1627        function transformHeritageClauses(nodes: NodeArray<HeritageClause> | undefined) {
1628            return factory.createNodeArray(filter(map(nodes, clause => factory.updateHeritageClause(clause, visitNodes(factory.createNodeArray(filter(clause.types, t => {
1629                return isEntityNameExpression(t.expression) || (clause.token === SyntaxKind.ExtendsKeyword && t.expression.kind === SyntaxKind.NullKeyword);
1630            })), visitDeclarationSubtree))), clause => clause.types && !!clause.types.length));
1631        }
1632    }
1633
1634    function isAlwaysType(node: Node) {
1635        if (node.kind === SyntaxKind.InterfaceDeclaration) {
1636            return true;
1637        }
1638        return false;
1639    }
1640
1641    // Elide "public" modifier, as it is the default
1642    function maskModifiers(node: Node, modifierMask?: ModifierFlags, modifierAdditions?: ModifierFlags): Modifier[] {
1643        return factory.createModifiersFromModifierFlags(maskModifierFlags(node, modifierMask, modifierAdditions));
1644    }
1645
1646    function maskModifierFlags(node: Node, modifierMask: ModifierFlags = ModifierFlags.All ^ ModifierFlags.Public, modifierAdditions: ModifierFlags = ModifierFlags.None): ModifierFlags {
1647        let flags = (getEffectiveModifierFlags(node) & modifierMask) | modifierAdditions;
1648        if (flags & ModifierFlags.Default && !(flags & ModifierFlags.Export)) {
1649            // A non-exported default is a nonsequitor - we usually try to remove all export modifiers
1650            // from statements in ambient declarations; but a default export must retain its export modifier to be syntactically valid
1651            flags ^= ModifierFlags.Export;
1652        }
1653        if (flags & ModifierFlags.Default && flags & ModifierFlags.Ambient) {
1654            flags ^= ModifierFlags.Ambient; // `declare` is never required alongside `default` (and would be an error if printed)
1655        }
1656        return flags;
1657    }
1658
1659    function getTypeAnnotationFromAccessor(accessor: AccessorDeclaration): TypeNode | undefined {
1660        if (accessor) {
1661            return accessor.kind === SyntaxKind.GetAccessor
1662                ? accessor.type // Getter - return type
1663                : accessor.parameters.length > 0
1664                    ? accessor.parameters[0].type // Setter parameter type
1665                    : undefined;
1666        }
1667    }
1668
1669    type CanHaveLiteralInitializer = VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration;
1670    function canHaveLiteralInitializer(node: Node): boolean {
1671        switch (node.kind) {
1672            case SyntaxKind.PropertyDeclaration:
1673            case SyntaxKind.PropertySignature:
1674                return !hasEffectiveModifier(node, ModifierFlags.Private);
1675            case SyntaxKind.Parameter:
1676            case SyntaxKind.VariableDeclaration:
1677                return true;
1678        }
1679        return false;
1680    }
1681
1682    type ProcessedDeclarationStatement =
1683        | FunctionDeclaration
1684        | ModuleDeclaration
1685        | ImportEqualsDeclaration
1686        | InterfaceDeclaration
1687        | ClassDeclaration
1688        | TypeAliasDeclaration
1689        | EnumDeclaration
1690        | VariableStatement
1691        | ImportDeclaration
1692        | ExportDeclaration
1693        | ExportAssignment;
1694
1695    function isPreservedDeclarationStatement(node: Node): node is ProcessedDeclarationStatement {
1696        switch (node.kind) {
1697            case SyntaxKind.FunctionDeclaration:
1698            case SyntaxKind.ModuleDeclaration:
1699            case SyntaxKind.ImportEqualsDeclaration:
1700            case SyntaxKind.InterfaceDeclaration:
1701            case SyntaxKind.ClassDeclaration:
1702            case SyntaxKind.StructDeclaration:
1703            case SyntaxKind.TypeAliasDeclaration:
1704            case SyntaxKind.EnumDeclaration:
1705            case SyntaxKind.VariableStatement:
1706            case SyntaxKind.ImportDeclaration:
1707            case SyntaxKind.ExportDeclaration:
1708            case SyntaxKind.ExportAssignment:
1709                return true;
1710        }
1711        return false;
1712    }
1713
1714    type ProcessedComponent =
1715        | ConstructSignatureDeclaration
1716        | ConstructorDeclaration
1717        | MethodDeclaration
1718        | GetAccessorDeclaration
1719        | SetAccessorDeclaration
1720        | PropertyDeclaration
1721        | PropertySignature
1722        | MethodSignature
1723        | CallSignatureDeclaration
1724        | IndexSignatureDeclaration
1725        | VariableDeclaration
1726        | TypeParameterDeclaration
1727        | ExpressionWithTypeArguments
1728        | TypeReferenceNode
1729        | ConditionalTypeNode
1730        | FunctionTypeNode
1731        | ConstructorTypeNode
1732        | ImportTypeNode;
1733
1734    function isProcessedComponent(node: Node): node is ProcessedComponent {
1735        switch (node.kind) {
1736            case SyntaxKind.ConstructSignature:
1737            case SyntaxKind.Constructor:
1738            case SyntaxKind.MethodDeclaration:
1739            case SyntaxKind.GetAccessor:
1740            case SyntaxKind.SetAccessor:
1741            case SyntaxKind.PropertyDeclaration:
1742            case SyntaxKind.PropertySignature:
1743            case SyntaxKind.MethodSignature:
1744            case SyntaxKind.CallSignature:
1745            case SyntaxKind.IndexSignature:
1746            case SyntaxKind.VariableDeclaration:
1747            case SyntaxKind.TypeParameter:
1748            case SyntaxKind.ExpressionWithTypeArguments:
1749            case SyntaxKind.TypeReference:
1750            case SyntaxKind.ConditionalType:
1751            case SyntaxKind.FunctionType:
1752            case SyntaxKind.ConstructorType:
1753            case SyntaxKind.ImportType:
1754                return true;
1755        }
1756        return false;
1757    }
1758}
1759