• 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 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 (npm may disambiguate module
402                        // references when installing this package, making the path is unreliable).
403                        if (startsWith(fileName, "node_modules/") || pathContainsNodeModules(fileName)) {
404                            return;
405                        }
406
407                        references.push({ pos: -1, end: -1, fileName });
408                    }
409                };
410            }
411        }
412
413        function collectReferences(sourceFile: SourceFile | UnparsedSource, ret: ESMap<NodeId, SourceFile>) {
414            if (noResolve || (!isUnparsedSource(sourceFile) && isSourceFileJS(sourceFile))) return ret;
415            forEach(sourceFile.referencedFiles, f => {
416                const elem = host.getSourceFileFromReference(sourceFile, f);
417                if (elem) {
418                    ret.set(getOriginalNodeId(elem), elem);
419                }
420            });
421            return ret;
422        }
423
424        function collectLibs(sourceFile: SourceFile | UnparsedSource, ret: ESMap<string, boolean>) {
425            forEach(sourceFile.libReferenceDirectives, ref => {
426                const lib = host.getLibFileFromReference(ref);
427                if (lib) {
428                    ret.set(toFileNameLowerCase(ref.fileName), true);
429                }
430            });
431            return ret;
432        }
433
434        function filterBindingPatternInitializers(name: BindingName) {
435            if (name.kind === SyntaxKind.Identifier) {
436                return name;
437            }
438            else {
439                if (name.kind === SyntaxKind.ArrayBindingPattern) {
440                    return factory.updateArrayBindingPattern(name, visitNodes(name.elements, visitBindingElement));
441                }
442                else {
443                    return factory.updateObjectBindingPattern(name, visitNodes(name.elements, visitBindingElement));
444                }
445            }
446
447            function visitBindingElement<T extends ArrayBindingElement>(elem: T): T;
448            function visitBindingElement(elem: ArrayBindingElement): ArrayBindingElement {
449                if (elem.kind === SyntaxKind.OmittedExpression) {
450                    return elem;
451                }
452                return factory.updateBindingElement(elem, elem.dotDotDotToken, elem.propertyName, filterBindingPatternInitializers(elem.name), shouldPrintWithInitializer(elem) ? elem.initializer : undefined);
453            }
454        }
455
456        function ensureParameter(p: ParameterDeclaration, modifierMask?: ModifierFlags, type?: TypeNode): ParameterDeclaration {
457            let oldDiag: typeof getSymbolAccessibilityDiagnostic | undefined;
458            if (!suppressNewDiagnosticContexts) {
459                oldDiag = getSymbolAccessibilityDiagnostic;
460                getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(p);
461            }
462            const newParam = factory.updateParameterDeclaration(
463                p,
464                /*decorators*/ undefined,
465                maskModifiers(p, modifierMask),
466                p.dotDotDotToken,
467                filterBindingPatternInitializers(p.name),
468                resolver.isOptionalParameter(p) ? (p.questionToken || factory.createToken(SyntaxKind.QuestionToken)) : undefined,
469                ensureType(p, type || p.type, /*ignorePrivate*/ true), // Ignore private param props, since this type is going straight back into a param
470                ensureNoInitializer(p)
471            );
472            if (!suppressNewDiagnosticContexts) {
473                getSymbolAccessibilityDiagnostic = oldDiag!;
474            }
475            return newParam;
476        }
477
478        function shouldPrintWithInitializer(node: Node) {
479            return canHaveLiteralInitializer(node) && resolver.isLiteralConstDeclaration(getParseTreeNode(node) as CanHaveLiteralInitializer); // TODO: Make safe
480        }
481
482        function ensureNoInitializer(node: CanHaveLiteralInitializer) {
483            if (shouldPrintWithInitializer(node)) {
484                return resolver.createLiteralConstValue(getParseTreeNode(node) as CanHaveLiteralInitializer, symbolTracker); // TODO: Make safe
485            }
486            return undefined;
487        }
488
489        type HasInferredType =
490            | FunctionDeclaration
491            | MethodDeclaration
492            | GetAccessorDeclaration
493            | SetAccessorDeclaration
494            | BindingElement
495            | ConstructSignatureDeclaration
496            | VariableDeclaration
497            | MethodSignature
498            | CallSignatureDeclaration
499            | ParameterDeclaration
500            | PropertyDeclaration
501            | PropertySignature;
502
503        function ensureType(node: HasInferredType, type: TypeNode | undefined, ignorePrivate?: boolean): TypeNode | undefined {
504            if (!ignorePrivate && hasEffectiveModifier(node, ModifierFlags.Private)) {
505                // Private nodes emit no types (except private parameter properties, whose parameter types are actually visible)
506                return;
507            }
508            if (shouldPrintWithInitializer(node)) {
509                // Literal const declarations will have an initializer ensured rather than a type
510                return;
511            }
512            const shouldUseResolverType = node.kind === SyntaxKind.Parameter &&
513                (resolver.isRequiredInitializedParameter(node) ||
514                 resolver.isOptionalUninitializedParameterProperty(node));
515            if (type && !shouldUseResolverType) {
516                return visitNode(type, visitDeclarationSubtree);
517            }
518            if (!getParseTreeNode(node)) {
519                return type ? visitNode(type, visitDeclarationSubtree) : factory.createKeywordTypeNode(SyntaxKind.AnyKeyword);
520            }
521            if (node.kind === SyntaxKind.SetAccessor) {
522                // 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
523                // (The inferred type here will be void, but the old declaration emitter printed `any`, so this replicates that)
524                return factory.createKeywordTypeNode(SyntaxKind.AnyKeyword);
525            }
526            errorNameNode = node.name;
527            let oldDiag: typeof getSymbolAccessibilityDiagnostic;
528            if (!suppressNewDiagnosticContexts) {
529                oldDiag = getSymbolAccessibilityDiagnostic;
530                getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(node);
531            }
532            if (node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement) {
533                return cleanup(resolver.createTypeOfDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker));
534            }
535            if (node.kind === SyntaxKind.Parameter
536                || node.kind === SyntaxKind.PropertyDeclaration
537                || node.kind === SyntaxKind.PropertySignature) {
538                if (!node.initializer) return cleanup(resolver.createTypeOfDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker, shouldUseResolverType));
539                return cleanup(resolver.createTypeOfDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker, shouldUseResolverType) || resolver.createTypeOfExpression(node.initializer, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker));
540            }
541            return cleanup(resolver.createReturnTypeOfSignatureDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker));
542
543            function cleanup(returnValue: TypeNode | undefined) {
544                errorNameNode = undefined;
545                if (!suppressNewDiagnosticContexts) {
546                    getSymbolAccessibilityDiagnostic = oldDiag;
547                }
548                return returnValue || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword);
549            }
550        }
551
552        function isDeclarationAndNotVisible(node: NamedDeclaration) {
553            node = getParseTreeNode(node) as NamedDeclaration;
554            switch (node.kind) {
555                case SyntaxKind.FunctionDeclaration:
556                case SyntaxKind.ModuleDeclaration:
557                case SyntaxKind.InterfaceDeclaration:
558                case SyntaxKind.ClassDeclaration:
559                case SyntaxKind.TypeAliasDeclaration:
560                case SyntaxKind.EnumDeclaration:
561                    return !resolver.isDeclarationVisible(node);
562                // The following should be doing their own visibility checks based on filtering their members
563                case SyntaxKind.VariableDeclaration:
564                    return !getBindingNameVisible(node as VariableDeclaration);
565                case SyntaxKind.ImportEqualsDeclaration:
566                case SyntaxKind.ImportDeclaration:
567                case SyntaxKind.ExportDeclaration:
568                case SyntaxKind.ExportAssignment:
569                    return false;
570            }
571            return false;
572        }
573
574        function getBindingNameVisible(elem: BindingElement | VariableDeclaration | OmittedExpression): boolean {
575            if (isOmittedExpression(elem)) {
576                return false;
577            }
578            if (isBindingPattern(elem.name)) {
579                // If any child binding pattern element has been marked visible (usually by collect linked aliases), then this is visible
580                return some(elem.name.elements, getBindingNameVisible);
581            }
582            else {
583                return resolver.isDeclarationVisible(elem);
584            }
585        }
586
587        function updateParamsList(node: Node, params: NodeArray<ParameterDeclaration>, modifierMask?: ModifierFlags) {
588            if (hasEffectiveModifier(node, ModifierFlags.Private)) {
589                return undefined!; // TODO: GH#18217
590            }
591            const newParams = map(params, p => ensureParameter(p, modifierMask));
592            if (!newParams) {
593                return undefined!; // TODO: GH#18217
594            }
595            return factory.createNodeArray(newParams, params.hasTrailingComma);
596        }
597
598        function updateAccessorParamsList(input: AccessorDeclaration, isPrivate: boolean) {
599            let newParams: ParameterDeclaration[] | undefined;
600            if (!isPrivate) {
601                const thisParameter = getThisParameter(input);
602                if (thisParameter) {
603                    newParams = [ensureParameter(thisParameter)];
604                }
605            }
606            if (isSetAccessorDeclaration(input)) {
607                let newValueParameter: ParameterDeclaration | undefined;
608                if (!isPrivate) {
609                    const valueParameter = getSetAccessorValueParameter(input);
610                    if (valueParameter) {
611                        const accessorType = getTypeAnnotationFromAllAccessorDeclarations(input, resolver.getAllAccessorDeclarations(input));
612                        newValueParameter = ensureParameter(valueParameter, /*modifierMask*/ undefined, accessorType);
613                    }
614                }
615                if (!newValueParameter) {
616                    newValueParameter = factory.createParameterDeclaration(
617                        /*decorators*/ undefined,
618                        /*modifiers*/ undefined,
619                        /*dotDotDotToken*/ undefined,
620                        "value"
621                    );
622                }
623                newParams = append(newParams, newValueParameter);
624            }
625            return factory.createNodeArray(newParams || emptyArray);
626        }
627
628        function ensureTypeParams(node: Node, params: NodeArray<TypeParameterDeclaration> | undefined) {
629            return hasEffectiveModifier(node, ModifierFlags.Private) ? undefined : visitNodes(params, visitDeclarationSubtree);
630        }
631
632        function isEnclosingDeclaration(node: Node) {
633            return isSourceFile(node)
634                || isTypeAliasDeclaration(node)
635                || isModuleDeclaration(node)
636                || isClassDeclaration(node)
637                || isInterfaceDeclaration(node)
638                || isFunctionLike(node)
639                || isIndexSignatureDeclaration(node)
640                || isMappedTypeNode(node);
641        }
642
643        function checkEntityNameVisibility(entityName: EntityNameOrEntityNameExpression, enclosingDeclaration: Node) {
644            const visibilityResult = resolver.isEntityNameVisible(entityName, enclosingDeclaration);
645            handleSymbolAccessibilityError(visibilityResult);
646            recordTypeReferenceDirectivesIfNecessary(resolver.getTypeReferenceDirectivesForEntityName(entityName));
647        }
648
649        function preserveJsDoc<T extends Node>(updated: T, original: Node): T {
650            if (hasJSDocNodes(updated) && hasJSDocNodes(original)) {
651                updated.jsDoc = original.jsDoc;
652            }
653            return setCommentRange(updated, getCommentRange(original));
654        }
655
656        function rewriteModuleSpecifier<T extends Node>(parent: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration | ImportTypeNode, input: T | undefined): T | StringLiteral {
657            if (!input) return undefined!; // TODO: GH#18217
658            resultHasExternalModuleIndicator = resultHasExternalModuleIndicator || (parent.kind !== SyntaxKind.ModuleDeclaration && parent.kind !== SyntaxKind.ImportType);
659            if (isStringLiteralLike(input)) {
660                if (isBundledEmit) {
661                    const newName = getExternalModuleNameFromDeclaration(context.getEmitHost(), resolver, parent);
662                    if (newName) {
663                        return factory.createStringLiteral(newName);
664                    }
665                }
666                else {
667                    const symbol = resolver.getSymbolOfExternalModuleSpecifier(input);
668                    if (symbol) {
669                        (exportedModulesFromDeclarationEmit || (exportedModulesFromDeclarationEmit = [])).push(symbol);
670                    }
671                }
672            }
673            return input;
674        }
675
676        function transformImportEqualsDeclaration(decl: ImportEqualsDeclaration) {
677            if (!resolver.isDeclarationVisible(decl)) return;
678            if (decl.moduleReference.kind === SyntaxKind.ExternalModuleReference) {
679                // Rewrite external module names if necessary
680                const specifier = getExternalModuleImportEqualsDeclarationExpression(decl);
681                return factory.updateImportEqualsDeclaration(
682                    decl,
683                    /*decorators*/ undefined,
684                    decl.modifiers,
685                    decl.isTypeOnly,
686                    decl.name,
687                    factory.updateExternalModuleReference(decl.moduleReference, rewriteModuleSpecifier(decl, specifier))
688                );
689            }
690            else {
691                const oldDiag = getSymbolAccessibilityDiagnostic;
692                getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(decl);
693                checkEntityNameVisibility(decl.moduleReference, enclosingDeclaration);
694                getSymbolAccessibilityDiagnostic = oldDiag;
695                return decl;
696            }
697        }
698
699        function transformImportDeclaration(decl: ImportDeclaration) {
700            if (!decl.importClause) {
701                // import "mod" - possibly needed for side effects? (global interface patches, module augmentations, etc)
702                return factory.updateImportDeclaration(
703                    decl,
704                    /*decorators*/ undefined,
705                    decl.modifiers,
706                    decl.importClause,
707                    rewriteModuleSpecifier(decl, decl.moduleSpecifier)
708                );
709            }
710            // The `importClause` visibility corresponds to the default's visibility.
711            const visibleDefaultBinding = decl.importClause && decl.importClause.name && resolver.isDeclarationVisible(decl.importClause) ? decl.importClause.name : undefined;
712            if (!decl.importClause.namedBindings) {
713                // No named bindings (either namespace or list), meaning the import is just default or should be elided
714                return visibleDefaultBinding && factory.updateImportDeclaration(decl, /*decorators*/ undefined, decl.modifiers, factory.updateImportClause(
715                    decl.importClause,
716                    decl.importClause.isTypeOnly,
717                    visibleDefaultBinding,
718                    /*namedBindings*/ undefined,
719                ), rewriteModuleSpecifier(decl, decl.moduleSpecifier));
720            }
721            if (decl.importClause.namedBindings.kind === SyntaxKind.NamespaceImport) {
722                // Namespace import (optionally with visible default)
723                const namedBindings = resolver.isDeclarationVisible(decl.importClause.namedBindings) ? decl.importClause.namedBindings : /*namedBindings*/ undefined;
724                return visibleDefaultBinding || namedBindings ? factory.updateImportDeclaration(decl, /*decorators*/ undefined, decl.modifiers, factory.updateImportClause(
725                    decl.importClause,
726                    decl.importClause.isTypeOnly,
727                    visibleDefaultBinding,
728                    namedBindings,
729                ), rewriteModuleSpecifier(decl, decl.moduleSpecifier)) : undefined;
730            }
731            // Named imports (optionally with visible default)
732            const bindingList = mapDefined(decl.importClause.namedBindings.elements, b => resolver.isDeclarationVisible(b) ? b : undefined);
733            if ((bindingList && bindingList.length) || visibleDefaultBinding) {
734                return factory.updateImportDeclaration(
735                    decl,
736                    /*decorators*/ undefined,
737                    decl.modifiers,
738                    factory.updateImportClause(
739                        decl.importClause,
740                        decl.importClause.isTypeOnly,
741                        visibleDefaultBinding,
742                        bindingList && bindingList.length ? factory.updateNamedImports(decl.importClause.namedBindings, bindingList) : undefined,
743                    ),
744                    rewriteModuleSpecifier(decl, decl.moduleSpecifier)
745                );
746            }
747            // Augmentation of export depends on import
748            if (resolver.isImportRequiredByAugmentation(decl)) {
749                return factory.updateImportDeclaration(
750                    decl,
751                    /*decorators*/ undefined,
752                    decl.modifiers,
753                    /*importClause*/ undefined,
754                    rewriteModuleSpecifier(decl, decl.moduleSpecifier)
755                );
756            }
757            // Nothing visible
758        }
759
760        function transformAndReplaceLatePaintedStatements(statements: NodeArray<Statement>): NodeArray<Statement> {
761            // This is a `while` loop because `handleSymbolAccessibilityError` can see additional import aliases marked as visible during
762            // error handling which must now be included in the output and themselves checked for errors.
763            // For example:
764            // ```
765            // module A {
766            //   export module Q {}
767            //   import B = Q;
768            //   import C = B;
769            //   export import D = C;
770            // }
771            // ```
772            // 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
773            // 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
774            // dependent imports and allowing a valid declaration file output. Today, this dependent alias marking only happens for internal import aliases.
775            while (length(lateMarkedStatements)) {
776                const i = lateMarkedStatements!.shift()!;
777                if (!isLateVisibilityPaintedStatement(i)) {
778                    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}`);
779                }
780                const priorNeedsDeclare = needsDeclare;
781                needsDeclare = i.parent && isSourceFile(i.parent) && !(isExternalModule(i.parent) && isBundledEmit);
782                const result = transformTopLevelDeclaration(i);
783                needsDeclare = priorNeedsDeclare;
784                lateStatementReplacementMap.set(getOriginalNodeId(i), result);
785            }
786
787            // And lastly, we need to get the final form of all those indetermine import declarations from before and add them to the output list
788            // (and remove them from the set to examine for outter declarations)
789            return visitNodes(statements, visitLateVisibilityMarkedStatements);
790
791            function visitLateVisibilityMarkedStatements(statement: Statement) {
792                if (isLateVisibilityPaintedStatement(statement)) {
793                    const key = getOriginalNodeId(statement);
794                    if (lateStatementReplacementMap.has(key)) {
795                        const result = lateStatementReplacementMap.get(key);
796                        lateStatementReplacementMap.delete(key);
797                        if (result) {
798                            if (isArray(result) ? some(result, needsScopeMarker) : needsScopeMarker(result)) {
799                                // Top-level declarations in .d.ts files are always considered exported even without a modifier unless there's an export assignment or specifier
800                                needsScopeFixMarker = true;
801                            }
802                            if (isSourceFile(statement.parent) && (isArray(result) ? some(result, isExternalModuleIndicator) : isExternalModuleIndicator(result))) {
803                                resultHasExternalModuleIndicator = true;
804                            }
805                        }
806                        return result;
807                    }
808                }
809                return statement;
810            }
811        }
812
813        function visitDeclarationSubtree(input: Node): VisitResult<Node> {
814            if (shouldStripInternal(input)) return;
815            if (isDeclaration(input)) {
816                if (isDeclarationAndNotVisible(input)) return;
817                if (hasDynamicName(input) && !resolver.isLateBound(getParseTreeNode(input) as Declaration)) {
818                    return;
819                }
820            }
821
822            // Elide implementation signatures from overload sets
823            if (isFunctionLike(input) && resolver.isImplementationOfOverload(input)) return;
824
825            // Elide semicolon class statements
826            if (isSemicolonClassElement(input)) return;
827
828            let previousEnclosingDeclaration: typeof enclosingDeclaration;
829            if (isEnclosingDeclaration(input)) {
830                previousEnclosingDeclaration = enclosingDeclaration;
831                enclosingDeclaration = input as Declaration;
832            }
833            const oldDiag = getSymbolAccessibilityDiagnostic;
834
835            // Setup diagnostic-related flags before first potential `cleanup` call, otherwise
836            // We'd see a TDZ violation at runtime
837            const canProduceDiagnostic = canProduceDiagnostics(input);
838            const oldWithinObjectLiteralType = suppressNewDiagnosticContexts;
839            let shouldEnterSuppressNewDiagnosticsContextContext = ((input.kind === SyntaxKind.TypeLiteral || input.kind === SyntaxKind.MappedType) && input.parent.kind !== SyntaxKind.TypeAliasDeclaration);
840
841            // Emit methods which are private as properties with no type information
842            if (isMethodDeclaration(input) || isMethodSignature(input)) {
843                if (hasEffectiveModifier(input, ModifierFlags.Private)) {
844                    if (input.symbol && input.symbol.declarations && input.symbol.declarations[0] !== input) return; // Elide all but the first overload
845                    return cleanup(factory.createPropertyDeclaration(/*decorators*/ undefined, ensureModifiers(input), input.name, /*questionToken*/ undefined, /*type*/ undefined, /*initializer*/ undefined));
846                }
847            }
848
849            if (canProduceDiagnostic && !suppressNewDiagnosticContexts) {
850                getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(input as DeclarationDiagnosticProducing);
851            }
852
853            if (isTypeQueryNode(input)) {
854                checkEntityNameVisibility(input.exprName, enclosingDeclaration);
855            }
856
857            if (shouldEnterSuppressNewDiagnosticsContextContext) {
858                // 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.
859                suppressNewDiagnosticContexts = true;
860            }
861
862            if (isProcessedComponent(input)) {
863                switch (input.kind) {
864                    case SyntaxKind.ExpressionWithTypeArguments: {
865                        if ((isEntityName(input.expression) || isEntityNameExpression(input.expression))) {
866                            checkEntityNameVisibility(input.expression, enclosingDeclaration);
867                        }
868                        const node = visitEachChild(input, visitDeclarationSubtree, context);
869                        return cleanup(factory.updateExpressionWithTypeArguments(node, node.expression, node.typeArguments));
870                    }
871                    case SyntaxKind.TypeReference: {
872                        checkEntityNameVisibility(input.typeName, enclosingDeclaration);
873                        const node = visitEachChild(input, visitDeclarationSubtree, context);
874                        return cleanup(factory.updateTypeReferenceNode(node, node.typeName, node.typeArguments));
875                    }
876                    case SyntaxKind.ConstructSignature:
877                        return cleanup(factory.updateConstructSignature(
878                            input,
879                            ensureTypeParams(input, input.typeParameters),
880                            updateParamsList(input, input.parameters),
881                            ensureType(input, input.type)
882                        ));
883                    case SyntaxKind.Constructor: {
884                        // A constructor declaration may not have a type annotation
885                        const ctor = factory.createConstructorDeclaration(
886                            /*decorators*/ undefined,
887                            /*modifiers*/ ensureModifiers(input),
888                            updateParamsList(input, input.parameters, ModifierFlags.None),
889                            /*body*/ undefined
890                        );
891                        return cleanup(ctor);
892                    }
893                    case SyntaxKind.MethodDeclaration: {
894                        if (isPrivateIdentifier(input.name)) {
895                            return cleanup(/*returnValue*/ undefined);
896                        }
897                        const sig = factory.createMethodDeclaration(
898                            /*decorators*/ undefined,
899                            ensureModifiers(input),
900                            /*asteriskToken*/ undefined,
901                            input.name,
902                            input.questionToken,
903                            ensureTypeParams(input, input.typeParameters),
904                            updateParamsList(input, input.parameters),
905                            ensureType(input, input.type),
906                            /*body*/ undefined
907                        );
908                        return cleanup(sig);
909                    }
910                    case SyntaxKind.GetAccessor: {
911                        if (isPrivateIdentifier(input.name)) {
912                            return cleanup(/*returnValue*/ undefined);
913                        }
914                        const accessorType = getTypeAnnotationFromAllAccessorDeclarations(input, resolver.getAllAccessorDeclarations(input));
915                        return cleanup(factory.updateGetAccessorDeclaration(
916                            input,
917                            /*decorators*/ undefined,
918                            ensureModifiers(input),
919                            input.name,
920                            updateAccessorParamsList(input, hasEffectiveModifier(input, ModifierFlags.Private)),
921                            ensureType(input, accessorType),
922                            /*body*/ undefined));
923                    }
924                    case SyntaxKind.SetAccessor: {
925                        if (isPrivateIdentifier(input.name)) {
926                            return cleanup(/*returnValue*/ undefined);
927                        }
928                        return cleanup(factory.updateSetAccessorDeclaration(
929                            input,
930                            /*decorators*/ undefined,
931                            ensureModifiers(input),
932                            input.name,
933                            updateAccessorParamsList(input, hasEffectiveModifier(input, ModifierFlags.Private)),
934                            /*body*/ undefined));
935                    }
936                    case SyntaxKind.PropertyDeclaration:
937                        if (isPrivateIdentifier(input.name)) {
938                            return cleanup(/*returnValue*/ undefined);
939                        }
940                        return cleanup(factory.updatePropertyDeclaration(
941                            input,
942                            /*decorators*/ undefined,
943                            ensureModifiers(input),
944                            input.name,
945                            input.questionToken,
946                            ensureType(input, input.type),
947                            ensureNoInitializer(input)
948                        ));
949                    case SyntaxKind.PropertySignature:
950                        if (isPrivateIdentifier(input.name)) {
951                            return cleanup(/*returnValue*/ undefined);
952                        }
953                        return cleanup(factory.updatePropertySignature(
954                            input,
955                            ensureModifiers(input),
956                            input.name,
957                            input.questionToken,
958                            ensureType(input, input.type)
959                        ));
960                    case SyntaxKind.MethodSignature: {
961                        if (isPrivateIdentifier(input.name)) {
962                            return cleanup(/*returnValue*/ undefined);
963                        }
964                        return cleanup(factory.updateMethodSignature(
965                            input,
966                            ensureModifiers(input),
967                            input.name,
968                            input.questionToken,
969                            ensureTypeParams(input, input.typeParameters),
970                            updateParamsList(input, input.parameters),
971                            ensureType(input, input.type)
972                        ));
973                    }
974                    case SyntaxKind.CallSignature: {
975                        return cleanup(factory.updateCallSignature(
976                            input,
977                            ensureTypeParams(input, input.typeParameters),
978                            updateParamsList(input, input.parameters),
979                            ensureType(input, input.type)
980                        ));
981                    }
982                    case SyntaxKind.IndexSignature: {
983                        return cleanup(factory.updateIndexSignature(
984                            input,
985                            /*decorators*/ undefined,
986                            ensureModifiers(input),
987                            updateParamsList(input, input.parameters),
988                            visitNode(input.type, visitDeclarationSubtree) || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword)
989                        ));
990                    }
991                    case SyntaxKind.VariableDeclaration: {
992                        if (isBindingPattern(input.name)) {
993                            return recreateBindingPattern(input.name);
994                        }
995                        shouldEnterSuppressNewDiagnosticsContextContext = true;
996                        suppressNewDiagnosticContexts = true; // Variable declaration types also suppress new diagnostic contexts, provided the contexts wouldn't be made for binding pattern types
997                        return cleanup(factory.updateVariableDeclaration(input, input.name, /*exclamationToken*/ undefined, ensureType(input, input.type), ensureNoInitializer(input)));
998                    }
999                    case SyntaxKind.TypeParameter: {
1000                        if (isPrivateMethodTypeParameter(input) && (input.default || input.constraint)) {
1001                            return cleanup(factory.updateTypeParameterDeclaration(input, input.name, /*constraint*/ undefined, /*defaultType*/ undefined));
1002                        }
1003                        return cleanup(visitEachChild(input, visitDeclarationSubtree, context));
1004                    }
1005                    case SyntaxKind.ConditionalType: {
1006                        // We have to process conditional types in a special way because for visibility purposes we need to push a new enclosingDeclaration
1007                        // just for the `infer` types in the true branch. It's an implicit declaration scope that only applies to _part_ of the type.
1008                        const checkType = visitNode(input.checkType, visitDeclarationSubtree);
1009                        const extendsType = visitNode(input.extendsType, visitDeclarationSubtree);
1010                        const oldEnclosingDecl = enclosingDeclaration;
1011                        enclosingDeclaration = input.trueType;
1012                        const trueType = visitNode(input.trueType, visitDeclarationSubtree);
1013                        enclosingDeclaration = oldEnclosingDecl;
1014                        const falseType = visitNode(input.falseType, visitDeclarationSubtree);
1015                        return cleanup(factory.updateConditionalTypeNode(input, checkType, extendsType, trueType, falseType));
1016                    }
1017                    case SyntaxKind.FunctionType: {
1018                        return cleanup(factory.updateFunctionTypeNode(input, visitNodes(input.typeParameters, visitDeclarationSubtree), updateParamsList(input, input.parameters), visitNode(input.type, visitDeclarationSubtree)));
1019                    }
1020                    case SyntaxKind.ConstructorType: {
1021                        return cleanup(factory.updateConstructorTypeNode(input, ensureModifiers(input), visitNodes(input.typeParameters, visitDeclarationSubtree), updateParamsList(input, input.parameters), visitNode(input.type, visitDeclarationSubtree)));
1022                    }
1023                    case SyntaxKind.ImportType: {
1024                        if (!isLiteralImportTypeNode(input)) return cleanup(input);
1025                        return cleanup(factory.updateImportTypeNode(
1026                            input,
1027                            factory.updateLiteralTypeNode(input.argument, rewriteModuleSpecifier(input, input.argument.literal)),
1028                            input.qualifier,
1029                            visitNodes(input.typeArguments, visitDeclarationSubtree, isTypeNode),
1030                            input.isTypeOf
1031                        ));
1032                    }
1033                    default: Debug.assertNever(input, `Attempted to process unhandled node kind: ${(ts as any).SyntaxKind[(input as any).kind]}`);
1034                }
1035            }
1036
1037            if (isTupleTypeNode(input) && (getLineAndCharacterOfPosition(currentSourceFile, input.pos).line === getLineAndCharacterOfPosition(currentSourceFile, input.end).line)) {
1038                setEmitFlags(input, EmitFlags.SingleLine);
1039            }
1040
1041            return cleanup(visitEachChild(input, visitDeclarationSubtree, context));
1042
1043            function cleanup<T extends Node>(returnValue: T | undefined): T | undefined {
1044                if (returnValue && canProduceDiagnostic && hasDynamicName(input as Declaration)) {
1045                    checkName(input as DeclarationDiagnosticProducing);
1046                }
1047                if (isEnclosingDeclaration(input)) {
1048                    enclosingDeclaration = previousEnclosingDeclaration;
1049                }
1050                if (canProduceDiagnostic && !suppressNewDiagnosticContexts) {
1051                    getSymbolAccessibilityDiagnostic = oldDiag;
1052                }
1053                if (shouldEnterSuppressNewDiagnosticsContextContext) {
1054                    suppressNewDiagnosticContexts = oldWithinObjectLiteralType;
1055                }
1056                if (returnValue === input) {
1057                    return returnValue;
1058                }
1059                return returnValue && setOriginalNode(preserveJsDoc(returnValue, input), input);
1060            }
1061        }
1062
1063        function isPrivateMethodTypeParameter(node: TypeParameterDeclaration) {
1064            return node.parent.kind === SyntaxKind.MethodDeclaration && hasEffectiveModifier(node.parent, ModifierFlags.Private);
1065        }
1066
1067        function visitDeclarationStatements(input: Node): VisitResult<Node> {
1068            if (!isPreservedDeclarationStatement(input)) {
1069                // return undefined for unmatched kinds to omit them from the tree
1070                return;
1071            }
1072            if (shouldStripInternal(input)) return;
1073
1074            switch (input.kind) {
1075                case SyntaxKind.ExportDeclaration: {
1076                    if (isSourceFile(input.parent)) {
1077                        resultHasExternalModuleIndicator = true;
1078                    }
1079                    resultHasScopeMarker = true;
1080                    // Always visible if the parent node isn't dropped for being not visible
1081                    // Rewrite external module names if necessary
1082                    return factory.updateExportDeclaration(
1083                        input,
1084                        /*decorators*/ undefined,
1085                        input.modifiers,
1086                        input.isTypeOnly,
1087                        input.exportClause,
1088                        rewriteModuleSpecifier(input, input.moduleSpecifier),
1089                    );
1090                }
1091                case SyntaxKind.ExportAssignment: {
1092                    // Always visible if the parent node isn't dropped for being not visible
1093                    if (isSourceFile(input.parent)) {
1094                        resultHasExternalModuleIndicator = true;
1095                    }
1096                    resultHasScopeMarker = true;
1097                    if (input.expression.kind === SyntaxKind.Identifier) {
1098                        return input;
1099                    }
1100                    else {
1101                        const newId = factory.createUniqueName("_default", GeneratedIdentifierFlags.Optimistic);
1102                        getSymbolAccessibilityDiagnostic = () => ({
1103                            diagnosticMessage: Diagnostics.Default_export_of_the_module_has_or_is_using_private_name_0,
1104                            errorNode: input
1105                        });
1106                        errorFallbackNode = input;
1107                        const varDecl = factory.createVariableDeclaration(newId, /*exclamationToken*/ undefined, resolver.createTypeOfExpression(input.expression, input, declarationEmitNodeBuilderFlags, symbolTracker), /*initializer*/ undefined);
1108                        errorFallbackNode = undefined;
1109                        const statement = factory.createVariableStatement(needsDeclare ? [factory.createModifier(SyntaxKind.DeclareKeyword)] : [], factory.createVariableDeclarationList([varDecl], NodeFlags.Const));
1110                        return [statement, factory.updateExportAssignment(input, input.decorators, input.modifiers, newId)];
1111                    }
1112                }
1113            }
1114
1115            const result = transformTopLevelDeclaration(input);
1116            // Don't actually transform yet; just leave as original node - will be elided/swapped by late pass
1117            lateStatementReplacementMap.set(getOriginalNodeId(input), result);
1118            return input;
1119        }
1120
1121        function stripExportModifiers(statement: Statement): Statement {
1122            if (isImportEqualsDeclaration(statement) || hasEffectiveModifier(statement, ModifierFlags.Default) || !canHaveModifiers(statement)) {
1123                // `export import` statements should remain as-is, as imports are _not_ implicitly exported in an ambient namespace
1124                // Likewise, `export default` classes and the like and just be `default`, so we preserve their `export` modifiers, too
1125                return statement;
1126            }
1127
1128            const modifiers = factory.createModifiersFromModifierFlags(getEffectiveModifierFlags(statement) & (ModifierFlags.All ^ ModifierFlags.Export));
1129            return factory.updateModifiers(statement, modifiers);
1130        }
1131
1132        function transformTopLevelDeclaration(input: LateVisibilityPaintedStatement) {
1133            if (shouldStripInternal(input)) return;
1134            switch (input.kind) {
1135                case SyntaxKind.ImportEqualsDeclaration: {
1136                    return transformImportEqualsDeclaration(input);
1137                }
1138                case SyntaxKind.ImportDeclaration: {
1139                    return transformImportDeclaration(input);
1140                }
1141            }
1142            if (isDeclaration(input) && isDeclarationAndNotVisible(input)) return;
1143
1144            // Elide implementation signatures from overload sets
1145            if (isFunctionLike(input) && resolver.isImplementationOfOverload(input)) return;
1146
1147            let previousEnclosingDeclaration: typeof enclosingDeclaration;
1148            if (isEnclosingDeclaration(input)) {
1149                previousEnclosingDeclaration = enclosingDeclaration;
1150                enclosingDeclaration = input as Declaration;
1151            }
1152
1153            const canProdiceDiagnostic = canProduceDiagnostics(input);
1154            const oldDiag = getSymbolAccessibilityDiagnostic;
1155            if (canProdiceDiagnostic) {
1156                getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(input as DeclarationDiagnosticProducing);
1157            }
1158
1159            const previousNeedsDeclare = needsDeclare;
1160            switch (input.kind) {
1161                case SyntaxKind.TypeAliasDeclaration: // Type aliases get `declare`d if need be (for legacy support), but that's all
1162                    return cleanup(factory.updateTypeAliasDeclaration(
1163                        input,
1164                        /*decorators*/ undefined,
1165                        ensureModifiers(input),
1166                        input.name,
1167                        visitNodes(input.typeParameters, visitDeclarationSubtree, isTypeParameterDeclaration),
1168                        visitNode(input.type, visitDeclarationSubtree, isTypeNode)
1169                    ));
1170                case SyntaxKind.InterfaceDeclaration: {
1171                    return cleanup(factory.updateInterfaceDeclaration(
1172                        input,
1173                        /*decorators*/ undefined,
1174                        ensureModifiers(input),
1175                        input.name,
1176                        ensureTypeParams(input, input.typeParameters),
1177                        transformHeritageClauses(input.heritageClauses),
1178                        visitNodes(input.members, visitDeclarationSubtree)
1179                    ));
1180                }
1181                case SyntaxKind.FunctionDeclaration: {
1182                    // Generators lose their generator-ness, excepting their return type
1183                    const clean = cleanup(factory.updateFunctionDeclaration(
1184                        input,
1185                        /*decorators*/ undefined,
1186                        ensureModifiers(input),
1187                        /*asteriskToken*/ undefined,
1188                        input.name,
1189                        ensureTypeParams(input, input.typeParameters),
1190                        updateParamsList(input, input.parameters),
1191                        ensureType(input, input.type),
1192                        /*body*/ undefined
1193                    ));
1194                    if (clean && resolver.isExpandoFunctionDeclaration(input)) {
1195                        const props = resolver.getPropertiesOfContainerFunction(input);
1196                        // Use parseNodeFactory so it is usable as an enclosing declaration
1197                        const fakespace = parseNodeFactory.createModuleDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, clean.name || factory.createIdentifier("_default"), factory.createModuleBlock([]), NodeFlags.Namespace);
1198                        setParent(fakespace, enclosingDeclaration as SourceFile | NamespaceDeclaration);
1199                        fakespace.locals = createSymbolTable(props);
1200                        fakespace.symbol = props[0].parent!;
1201                        const exportMappings: [Identifier, string][] = [];
1202                        let declarations: (VariableStatement | ExportDeclaration)[] = mapDefined(props, p => {
1203                            if (!isPropertyAccessExpression(p.valueDeclaration)) {
1204                                return undefined; // TODO GH#33569: Handle element access expressions that created late bound names (rather than silently omitting them)
1205                            }
1206                            getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(p.valueDeclaration);
1207                            const type = resolver.createTypeOfDeclaration(p.valueDeclaration, fakespace, declarationEmitNodeBuilderFlags, symbolTracker);
1208                            getSymbolAccessibilityDiagnostic = oldDiag;
1209                            const nameStr = unescapeLeadingUnderscores(p.escapedName);
1210                            const isNonContextualKeywordName = isStringANonContextualKeyword(nameStr);
1211                            const name = isNonContextualKeywordName ? factory.getGeneratedNameForNode(p.valueDeclaration) : factory.createIdentifier(nameStr);
1212                            if (isNonContextualKeywordName) {
1213                                exportMappings.push([name, nameStr]);
1214                            }
1215                            const varDecl = factory.createVariableDeclaration(name, /*exclamationToken*/ undefined, type, /*initializer*/ undefined);
1216                            return factory.createVariableStatement(isNonContextualKeywordName ? undefined : [factory.createToken(SyntaxKind.ExportKeyword)], factory.createVariableDeclarationList([varDecl]));
1217                        });
1218                        if (!exportMappings.length) {
1219                            declarations = mapDefined(declarations, declaration => factory.updateModifiers(declaration, ModifierFlags.None));
1220                        }
1221                        else {
1222                            declarations.push(factory.createExportDeclaration(
1223                                /*decorators*/ undefined,
1224                                /*modifiers*/ undefined,
1225                                /*isTypeOnly*/ false,
1226                                factory.createNamedExports(map(exportMappings, ([gen, exp]) => {
1227                                    return factory.createExportSpecifier(gen, exp);
1228                                }))
1229                            ));
1230                        }
1231                        const namespaceDecl = factory.createModuleDeclaration(/*decorators*/ undefined, ensureModifiers(input), input.name!, factory.createModuleBlock(declarations), NodeFlags.Namespace);
1232                        if (!hasEffectiveModifier(clean, ModifierFlags.Default)) {
1233                            return [clean, namespaceDecl];
1234                        }
1235
1236                        const modifiers = factory.createModifiersFromModifierFlags((getEffectiveModifierFlags(clean) & ~ModifierFlags.ExportDefault) | ModifierFlags.Ambient);
1237                        const cleanDeclaration = factory.updateFunctionDeclaration(
1238                            clean,
1239                            /*decorators*/ undefined,
1240                            modifiers,
1241                            /*asteriskToken*/ undefined,
1242                            clean.name,
1243                            clean.typeParameters,
1244                            clean.parameters,
1245                            clean.type,
1246                            /*body*/ undefined
1247                        );
1248
1249                        const namespaceDeclaration = factory.updateModuleDeclaration(
1250                            namespaceDecl,
1251                            /*decorators*/ undefined,
1252                            modifiers,
1253                            namespaceDecl.name,
1254                            namespaceDecl.body
1255                        );
1256
1257                        const exportDefaultDeclaration = factory.createExportAssignment(
1258                            /*decorators*/ undefined,
1259                            /*modifiers*/ undefined,
1260                            /*isExportEquals*/ false,
1261                            namespaceDecl.name
1262                        );
1263
1264                        if (isSourceFile(input.parent)) {
1265                            resultHasExternalModuleIndicator = true;
1266                        }
1267                        resultHasScopeMarker = true;
1268
1269                        return [cleanDeclaration, namespaceDeclaration, exportDefaultDeclaration];
1270                    }
1271                    else {
1272                        return clean;
1273                    }
1274                }
1275                case SyntaxKind.ModuleDeclaration: {
1276                    needsDeclare = false;
1277                    const inner = input.body;
1278                    if (inner && inner.kind === SyntaxKind.ModuleBlock) {
1279                        const oldNeedsScopeFix = needsScopeFixMarker;
1280                        const oldHasScopeFix = resultHasScopeMarker;
1281                        resultHasScopeMarker = false;
1282                        needsScopeFixMarker = false;
1283                        const statements = visitNodes(inner.statements, visitDeclarationStatements);
1284                        let lateStatements = transformAndReplaceLatePaintedStatements(statements);
1285                        if (input.flags & NodeFlags.Ambient) {
1286                            needsScopeFixMarker = false; // If it was `declare`'d everything is implicitly exported already, ignore late printed "privates"
1287                        }
1288                        // With the final list of statements, there are 3 possibilities:
1289                        // 1. There's an export assignment or export declaration in the namespace - do nothing
1290                        // 2. Everything is exported and there are no export assignments or export declarations - strip all export modifiers
1291                        // 3. Some things are exported, some are not, and there's no marker - add an empty marker
1292                        if (!isGlobalScopeAugmentation(input) && !hasScopeMarker(lateStatements) && !resultHasScopeMarker) {
1293                            if (needsScopeFixMarker) {
1294                                lateStatements = factory.createNodeArray([...lateStatements, createEmptyExports(factory)]);
1295                            }
1296                            else {
1297                                lateStatements = visitNodes(lateStatements, stripExportModifiers);
1298                            }
1299                        }
1300                        const body = factory.updateModuleBlock(inner, lateStatements);
1301                        needsDeclare = previousNeedsDeclare;
1302                        needsScopeFixMarker = oldNeedsScopeFix;
1303                        resultHasScopeMarker = oldHasScopeFix;
1304                        const mods = ensureModifiers(input);
1305                        return cleanup(factory.updateModuleDeclaration(
1306                            input,
1307                            /*decorators*/ undefined,
1308                            mods,
1309                            isExternalModuleAugmentation(input) ? rewriteModuleSpecifier(input, input.name) : input.name,
1310                            body
1311                        ));
1312                    }
1313                    else {
1314                        needsDeclare = previousNeedsDeclare;
1315                        const mods = ensureModifiers(input);
1316                        needsDeclare = false;
1317                        visitNode(inner, visitDeclarationStatements);
1318                        // eagerly transform nested namespaces (the nesting doesn't need any elision or painting done)
1319                        const id = getOriginalNodeId(inner!); // TODO: GH#18217
1320                        const body = lateStatementReplacementMap.get(id);
1321                        lateStatementReplacementMap.delete(id);
1322                        return cleanup(factory.updateModuleDeclaration(
1323                            input,
1324                            /*decorators*/ undefined,
1325                            mods,
1326                            input.name,
1327                            body as ModuleBody
1328                        ));
1329                    }
1330                }
1331                case SyntaxKind.ClassDeclaration: {
1332                    errorNameNode = input.name;
1333                    errorFallbackNode = input;
1334                    const modifiers = factory.createNodeArray(ensureModifiers(input));
1335                    const typeParameters = ensureTypeParams(input, input.typeParameters);
1336                    const ctor = getFirstConstructorWithBody(input);
1337                    let parameterProperties: readonly PropertyDeclaration[] | undefined;
1338                    if (ctor) {
1339                        const oldDiag = getSymbolAccessibilityDiagnostic;
1340                        parameterProperties = compact(flatMap(ctor.parameters, (param) => {
1341                            if (!hasSyntacticModifier(param, ModifierFlags.ParameterPropertyModifier) || shouldStripInternal(param)) return;
1342                            getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(param);
1343                            if (param.name.kind === SyntaxKind.Identifier) {
1344                                return preserveJsDoc(factory.createPropertyDeclaration(
1345                                    /*decorators*/ undefined,
1346                                    ensureModifiers(param),
1347                                    param.name,
1348                                    param.questionToken,
1349                                    ensureType(param, param.type),
1350                                    ensureNoInitializer(param)), param);
1351                            }
1352                            else {
1353                                // Pattern - this is currently an error, but we emit declarations for it somewhat correctly
1354                                return walkBindingPattern(param.name);
1355                            }
1356
1357                            function walkBindingPattern(pattern: BindingPattern) {
1358                                let elems: PropertyDeclaration[] | undefined;
1359                                for (const elem of pattern.elements) {
1360                                    if (isOmittedExpression(elem)) continue;
1361                                    if (isBindingPattern(elem.name)) {
1362                                        elems = concatenate(elems, walkBindingPattern(elem.name));
1363                                    }
1364                                    elems = elems || [];
1365                                    elems.push(factory.createPropertyDeclaration(
1366                                        /*decorators*/ undefined,
1367                                        ensureModifiers(param),
1368                                        elem.name as Identifier,
1369                                        /*questionToken*/ undefined,
1370                                        ensureType(elem, /*type*/ undefined),
1371                                        /*initializer*/ undefined
1372                                    ));
1373                                }
1374                                return elems;
1375                            }
1376                        }));
1377                        getSymbolAccessibilityDiagnostic = oldDiag;
1378                    }
1379
1380                    const hasPrivateIdentifier = some(input.members, member => !!member.name && isPrivateIdentifier(member.name));
1381                    // When the class has at least one private identifier, create a unique constant identifier to retain the nominal typing behavior
1382                    // Prevents other classes with the same public members from being used in place of the current class
1383                    const privateIdentifier = hasPrivateIdentifier ? [
1384                        factory.createPropertyDeclaration(
1385                            /*decorators*/ undefined,
1386                            /*modifiers*/ undefined,
1387                            factory.createPrivateIdentifier("#private"),
1388                            /*questionToken*/ undefined,
1389                            /*type*/ undefined,
1390                            /*initializer*/ undefined
1391                        )
1392                    ] : undefined;
1393                    const memberNodes = concatenate(concatenate(privateIdentifier, parameterProperties), visitNodes(input.members, visitDeclarationSubtree));
1394                    const members = factory.createNodeArray(memberNodes);
1395
1396                    const extendsClause = getEffectiveBaseTypeNode(input);
1397                    if (extendsClause && !isEntityNameExpression(extendsClause.expression) && extendsClause.expression.kind !== SyntaxKind.NullKeyword) {
1398                        // We must add a temporary declaration for the extends clause expression
1399
1400                        const oldId = input.name ? unescapeLeadingUnderscores(input.name.escapedText) : "default";
1401                        const newId = factory.createUniqueName(`${oldId}_base`, GeneratedIdentifierFlags.Optimistic);
1402                        getSymbolAccessibilityDiagnostic = () => ({
1403                            diagnosticMessage: Diagnostics.extends_clause_of_exported_class_0_has_or_is_using_private_name_1,
1404                            errorNode: extendsClause,
1405                            typeName: input.name
1406                        });
1407                        const varDecl = factory.createVariableDeclaration(newId, /*exclamationToken*/ undefined, resolver.createTypeOfExpression(extendsClause.expression, input, declarationEmitNodeBuilderFlags, symbolTracker), /*initializer*/ undefined);
1408                        const statement = factory.createVariableStatement(needsDeclare ? [factory.createModifier(SyntaxKind.DeclareKeyword)] : [], factory.createVariableDeclarationList([varDecl], NodeFlags.Const));
1409                        const heritageClauses = factory.createNodeArray(map(input.heritageClauses, clause => {
1410                            if (clause.token === SyntaxKind.ExtendsKeyword) {
1411                                const oldDiag = getSymbolAccessibilityDiagnostic;
1412                                getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(clause.types[0]);
1413                                const newClause = factory.updateHeritageClause(clause, map(clause.types, t => factory.updateExpressionWithTypeArguments(t, newId, visitNodes(t.typeArguments, visitDeclarationSubtree))));
1414                                getSymbolAccessibilityDiagnostic = oldDiag;
1415                                return newClause;
1416                            }
1417                            return factory.updateHeritageClause(clause, visitNodes(factory.createNodeArray(filter(clause.types, t => isEntityNameExpression(t.expression) || t.expression.kind === SyntaxKind.NullKeyword)), visitDeclarationSubtree));
1418                        }));
1419                        return [statement, cleanup(factory.updateClassDeclaration(
1420                            input,
1421                            /*decorators*/ undefined,
1422                            modifiers,
1423                            input.name,
1424                            typeParameters,
1425                            heritageClauses,
1426                            members
1427                        ))!]; // TODO: GH#18217
1428                    }
1429                    else {
1430                        const heritageClauses = transformHeritageClauses(input.heritageClauses);
1431                        return cleanup(factory.updateClassDeclaration(
1432                            input,
1433                            /*decorators*/ undefined,
1434                            modifiers,
1435                            input.name,
1436                            typeParameters,
1437                            heritageClauses,
1438                            members
1439                        ));
1440                    }
1441                }
1442                case SyntaxKind.VariableStatement: {
1443                    return cleanup(transformVariableStatement(input));
1444                }
1445                case SyntaxKind.EnumDeclaration: {
1446                    return cleanup(factory.updateEnumDeclaration(input, /*decorators*/ undefined, factory.createNodeArray(ensureModifiers(input)), input.name, factory.createNodeArray(mapDefined(input.members, m => {
1447                        if (shouldStripInternal(m)) return;
1448                        // Rewrite enum values to their constants, if available
1449                        const constValue = resolver.getConstantValue(m);
1450                        return preserveJsDoc(factory.updateEnumMember(m, m.name, constValue !== undefined ? typeof constValue === "string" ? factory.createStringLiteral(constValue) : factory.createNumericLiteral(constValue) : undefined), m);
1451                    }))));
1452                }
1453            }
1454            // Anything left unhandled is an error, so this should be unreachable
1455            return Debug.assertNever(input, `Unhandled top-level node in declaration emit: ${(ts as any).SyntaxKind[(input as any).kind]}`);
1456
1457            function cleanup<T extends Node>(node: T | undefined): T | undefined {
1458                if (isEnclosingDeclaration(input)) {
1459                    enclosingDeclaration = previousEnclosingDeclaration;
1460                }
1461                if (canProdiceDiagnostic) {
1462                    getSymbolAccessibilityDiagnostic = oldDiag;
1463                }
1464                if (input.kind === SyntaxKind.ModuleDeclaration) {
1465                    needsDeclare = previousNeedsDeclare;
1466                }
1467                if (node as Node === input) {
1468                    return node;
1469                }
1470                errorFallbackNode = undefined;
1471                errorNameNode = undefined;
1472                return node && setOriginalNode(preserveJsDoc(node, input), input);
1473            }
1474        }
1475
1476        function transformVariableStatement(input: VariableStatement) {
1477            if (!forEach(input.declarationList.declarations, getBindingNameVisible)) return;
1478            const nodes = visitNodes(input.declarationList.declarations, visitDeclarationSubtree);
1479            if (!length(nodes)) return;
1480            return factory.updateVariableStatement(input, factory.createNodeArray(ensureModifiers(input)), factory.updateVariableDeclarationList(input.declarationList, nodes));
1481        }
1482
1483        function recreateBindingPattern(d: BindingPattern): VariableDeclaration[] {
1484            return flatten<VariableDeclaration>(mapDefined(d.elements, e => recreateBindingElement(e)));
1485        }
1486
1487        function recreateBindingElement(e: ArrayBindingElement) {
1488            if (e.kind === SyntaxKind.OmittedExpression) {
1489                return;
1490            }
1491            if (e.name) {
1492                if (!getBindingNameVisible(e)) return;
1493                if (isBindingPattern(e.name)) {
1494                    return recreateBindingPattern(e.name);
1495                }
1496                else {
1497                    return factory.createVariableDeclaration(e.name, /*exclamationToken*/ undefined, ensureType(e, /*type*/ undefined), /*initializer*/ undefined);
1498                }
1499            }
1500        }
1501
1502        function checkName(node: DeclarationDiagnosticProducing) {
1503            let oldDiag: typeof getSymbolAccessibilityDiagnostic | undefined;
1504            if (!suppressNewDiagnosticContexts) {
1505                oldDiag = getSymbolAccessibilityDiagnostic;
1506                getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNodeName(node);
1507            }
1508            errorNameNode = (node as NamedDeclaration).name;
1509            Debug.assert(resolver.isLateBound(getParseTreeNode(node) as Declaration)); // Should only be called with dynamic names
1510            const decl = node as NamedDeclaration as LateBoundDeclaration;
1511            const entityName = decl.name.expression;
1512            checkEntityNameVisibility(entityName, enclosingDeclaration);
1513            if (!suppressNewDiagnosticContexts) {
1514                getSymbolAccessibilityDiagnostic = oldDiag!;
1515            }
1516            errorNameNode = undefined;
1517        }
1518
1519        function shouldStripInternal(node: Node) {
1520            return !!stripInternal && !!node && isInternalDeclaration(node, currentSourceFile);
1521        }
1522
1523        function isScopeMarker(node: Node) {
1524            return isExportAssignment(node) || isExportDeclaration(node);
1525        }
1526
1527        function hasScopeMarker(statements: readonly Statement[]) {
1528            return some(statements, isScopeMarker);
1529        }
1530
1531        function ensureModifiers(node: Node): readonly Modifier[] | undefined {
1532            const currentFlags = getEffectiveModifierFlags(node);
1533            const newFlags = ensureModifierFlags(node);
1534            if (currentFlags === newFlags) {
1535                return node.modifiers;
1536            }
1537            return factory.createModifiersFromModifierFlags(newFlags);
1538        }
1539
1540        function ensureModifierFlags(node: Node): ModifierFlags {
1541            let mask = ModifierFlags.All ^ (ModifierFlags.Public | ModifierFlags.Async); // No async modifiers in declaration files
1542            let additions = (needsDeclare && !isAlwaysType(node)) ? ModifierFlags.Ambient : ModifierFlags.None;
1543            const parentIsFile = node.parent.kind === SyntaxKind.SourceFile;
1544            if (!parentIsFile || (isBundledEmit && parentIsFile && isExternalModule(node.parent as SourceFile))) {
1545                mask ^= ModifierFlags.Ambient;
1546                additions = ModifierFlags.None;
1547            }
1548            return maskModifierFlags(node, mask, additions);
1549        }
1550
1551        function getTypeAnnotationFromAllAccessorDeclarations(node: AccessorDeclaration, accessors: AllAccessorDeclarations) {
1552            let accessorType = getTypeAnnotationFromAccessor(node);
1553            if (!accessorType && node !== accessors.firstAccessor) {
1554                accessorType = getTypeAnnotationFromAccessor(accessors.firstAccessor);
1555                // 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
1556                getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(accessors.firstAccessor);
1557            }
1558            if (!accessorType && accessors.secondAccessor && node !== accessors.secondAccessor) {
1559                accessorType = getTypeAnnotationFromAccessor(accessors.secondAccessor);
1560                // 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
1561                getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(accessors.secondAccessor);
1562            }
1563            return accessorType;
1564        }
1565
1566        function transformHeritageClauses(nodes: NodeArray<HeritageClause> | undefined) {
1567            return factory.createNodeArray(filter(map(nodes, clause => factory.updateHeritageClause(clause, visitNodes(factory.createNodeArray(filter(clause.types, t => {
1568                return isEntityNameExpression(t.expression) || (clause.token === SyntaxKind.ExtendsKeyword && t.expression.kind === SyntaxKind.NullKeyword);
1569            })), visitDeclarationSubtree))), clause => clause.types && !!clause.types.length));
1570        }
1571    }
1572
1573    function isAlwaysType(node: Node) {
1574        if (node.kind === SyntaxKind.InterfaceDeclaration) {
1575            return true;
1576        }
1577        return false;
1578    }
1579
1580    // Elide "public" modifier, as it is the default
1581    function maskModifiers(node: Node, modifierMask?: ModifierFlags, modifierAdditions?: ModifierFlags): Modifier[] {
1582        return factory.createModifiersFromModifierFlags(maskModifierFlags(node, modifierMask, modifierAdditions));
1583    }
1584
1585    function maskModifierFlags(node: Node, modifierMask: ModifierFlags = ModifierFlags.All ^ ModifierFlags.Public, modifierAdditions: ModifierFlags = ModifierFlags.None): ModifierFlags {
1586        let flags = (getEffectiveModifierFlags(node) & modifierMask) | modifierAdditions;
1587        if (flags & ModifierFlags.Default && !(flags & ModifierFlags.Export)) {
1588            // A non-exported default is a nonsequitor - we usually try to remove all export modifiers
1589            // from statements in ambient declarations; but a default export must retain its export modifier to be syntactically valid
1590            flags ^= ModifierFlags.Export;
1591        }
1592        if (flags & ModifierFlags.Default && flags & ModifierFlags.Ambient) {
1593            flags ^= ModifierFlags.Ambient; // `declare` is never required alongside `default` (and would be an error if printed)
1594        }
1595        return flags;
1596    }
1597
1598    function getTypeAnnotationFromAccessor(accessor: AccessorDeclaration): TypeNode | undefined {
1599        if (accessor) {
1600            return accessor.kind === SyntaxKind.GetAccessor
1601                ? accessor.type // Getter - return type
1602                : accessor.parameters.length > 0
1603                    ? accessor.parameters[0].type // Setter parameter type
1604                    : undefined;
1605        }
1606    }
1607
1608    type CanHaveLiteralInitializer = VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration;
1609    function canHaveLiteralInitializer(node: Node): boolean {
1610        switch (node.kind) {
1611            case SyntaxKind.PropertyDeclaration:
1612            case SyntaxKind.PropertySignature:
1613                return !hasEffectiveModifier(node, ModifierFlags.Private);
1614            case SyntaxKind.Parameter:
1615            case SyntaxKind.VariableDeclaration:
1616                return true;
1617        }
1618        return false;
1619    }
1620
1621    type ProcessedDeclarationStatement =
1622        | FunctionDeclaration
1623        | ModuleDeclaration
1624        | ImportEqualsDeclaration
1625        | InterfaceDeclaration
1626        | ClassDeclaration
1627        | TypeAliasDeclaration
1628        | EnumDeclaration
1629        | VariableStatement
1630        | ImportDeclaration
1631        | ExportDeclaration
1632        | ExportAssignment;
1633
1634    function isPreservedDeclarationStatement(node: Node): node is ProcessedDeclarationStatement {
1635        switch (node.kind) {
1636            case SyntaxKind.FunctionDeclaration:
1637            case SyntaxKind.ModuleDeclaration:
1638            case SyntaxKind.ImportEqualsDeclaration:
1639            case SyntaxKind.InterfaceDeclaration:
1640            case SyntaxKind.ClassDeclaration:
1641            case SyntaxKind.TypeAliasDeclaration:
1642            case SyntaxKind.EnumDeclaration:
1643            case SyntaxKind.VariableStatement:
1644            case SyntaxKind.ImportDeclaration:
1645            case SyntaxKind.ExportDeclaration:
1646            case SyntaxKind.ExportAssignment:
1647                return true;
1648        }
1649        return false;
1650    }
1651
1652    type ProcessedComponent =
1653        | ConstructSignatureDeclaration
1654        | ConstructorDeclaration
1655        | MethodDeclaration
1656        | GetAccessorDeclaration
1657        | SetAccessorDeclaration
1658        | PropertyDeclaration
1659        | PropertySignature
1660        | MethodSignature
1661        | CallSignatureDeclaration
1662        | IndexSignatureDeclaration
1663        | VariableDeclaration
1664        | TypeParameterDeclaration
1665        | ExpressionWithTypeArguments
1666        | TypeReferenceNode
1667        | ConditionalTypeNode
1668        | FunctionTypeNode
1669        | ConstructorTypeNode
1670        | ImportTypeNode;
1671
1672    function isProcessedComponent(node: Node): node is ProcessedComponent {
1673        switch (node.kind) {
1674            case SyntaxKind.ConstructSignature:
1675            case SyntaxKind.Constructor:
1676            case SyntaxKind.MethodDeclaration:
1677            case SyntaxKind.GetAccessor:
1678            case SyntaxKind.SetAccessor:
1679            case SyntaxKind.PropertyDeclaration:
1680            case SyntaxKind.PropertySignature:
1681            case SyntaxKind.MethodSignature:
1682            case SyntaxKind.CallSignature:
1683            case SyntaxKind.IndexSignature:
1684            case SyntaxKind.VariableDeclaration:
1685            case SyntaxKind.TypeParameter:
1686            case SyntaxKind.ExpressionWithTypeArguments:
1687            case SyntaxKind.TypeReference:
1688            case SyntaxKind.ConditionalType:
1689            case SyntaxKind.FunctionType:
1690            case SyntaxKind.ConstructorType:
1691            case SyntaxKind.ImportType:
1692                return true;
1693        }
1694        return false;
1695    }
1696}
1697