• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1namespace ts {
2    const brackets = createBracketsMap();
3
4    /*@internal*/
5    export function isBuildInfoFile(file: string) {
6        return fileExtensionIs(file, Extension.TsBuildInfo);
7    }
8
9    /*@internal*/
10    /**
11     * Iterates over the source files that are expected to have an emit output.
12     *
13     * @param host An EmitHost.
14     * @param action The action to execute.
15     * @param sourceFilesOrTargetSourceFile
16     *   If an array, the full list of source files to emit.
17     *   Else, calls `getSourceFilesToEmit` with the (optional) target source file to determine the list of source files to emit.
18     */
19    export function forEachEmittedFile<T>(
20        host: EmitHost, action: (emitFileNames: EmitFileNames, sourceFileOrBundle: SourceFile | Bundle | undefined) => T,
21        sourceFilesOrTargetSourceFile?: readonly SourceFile[] | SourceFile,
22        forceDtsEmit = false,
23        onlyBuildInfo?: boolean,
24        includeBuildInfo?: boolean) {
25        const sourceFiles = isArray(sourceFilesOrTargetSourceFile) ? sourceFilesOrTargetSourceFile : getSourceFilesToEmit(host, sourceFilesOrTargetSourceFile, forceDtsEmit);
26        const options = host.getCompilerOptions();
27        if (outFile(options)) {
28            const prepends = host.getPrependNodes();
29            if (sourceFiles.length || prepends.length) {
30                const bundle = factory.createBundle(sourceFiles, prepends);
31                const result = action(getOutputPathsFor(bundle, host, forceDtsEmit), bundle);
32                if (result) {
33                    return result;
34                }
35            }
36        }
37        else {
38            if (!onlyBuildInfo) {
39                for (const sourceFile of sourceFiles) {
40                    const result = action(getOutputPathsFor(sourceFile, host, forceDtsEmit), sourceFile);
41                    if (result) {
42                        return result;
43                    }
44                }
45            }
46            if (includeBuildInfo) {
47                const buildInfoPath = getTsBuildInfoEmitOutputFilePath(options);
48                if (buildInfoPath) return action({ buildInfoPath }, /*sourceFileOrBundle*/ undefined);
49            }
50        }
51    }
52
53    export function getTsBuildInfoEmitOutputFilePath(options: CompilerOptions) {
54        const configFile = options.configFilePath;
55        if (!isIncrementalCompilation(options)) return undefined;
56        if (options.tsBuildInfoFile) return options.tsBuildInfoFile;
57        const outPath = outFile(options);
58        let buildInfoExtensionLess: string;
59        if (outPath) {
60            buildInfoExtensionLess = removeFileExtension(outPath);
61        }
62        else {
63            if (!configFile) return undefined;
64            const configFileExtensionLess = removeFileExtension(configFile);
65            buildInfoExtensionLess = options.outDir ?
66                options.rootDir ?
67                    resolvePath(options.outDir, getRelativePathFromDirectory(options.rootDir, configFileExtensionLess, /*ignoreCase*/ true)) :
68                    combinePaths(options.outDir, getBaseFileName(configFileExtensionLess)) :
69                configFileExtensionLess;
70        }
71        return buildInfoExtensionLess + Extension.TsBuildInfo;
72    }
73
74    /*@internal*/
75    export function getOutputPathsForBundle(options: CompilerOptions, forceDtsPaths: boolean): EmitFileNames {
76        const outPath = outFile(options)!;
77        const jsFilePath = options.emitDeclarationOnly ? undefined : outPath;
78        const sourceMapFilePath = jsFilePath && getSourceMapFilePath(jsFilePath, options);
79        const declarationFilePath = (forceDtsPaths || getEmitDeclarations(options)) ? removeFileExtension(outPath) + Extension.Dts : undefined;
80        const declarationMapPath = declarationFilePath && getAreDeclarationMapsEnabled(options) ? declarationFilePath + ".map" : undefined;
81        const buildInfoPath = getTsBuildInfoEmitOutputFilePath(options);
82        return { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, buildInfoPath };
83    }
84
85    /*@internal*/
86    export function getOutputPathsFor(sourceFile: SourceFile | Bundle, host: EmitHost, forceDtsPaths: boolean): EmitFileNames {
87        const options = host.getCompilerOptions();
88        if (sourceFile.kind === SyntaxKind.Bundle) {
89            return getOutputPathsForBundle(options, forceDtsPaths);
90        }
91        else {
92            const ownOutputFilePath = getOwnEmitOutputFilePath(sourceFile.fileName, host, getOutputExtension(sourceFile.fileName, options));
93            const isJsonFile = isJsonSourceFile(sourceFile);
94            // If json file emits to the same location skip writing it, if emitDeclarationOnly skip writing it
95            const isJsonEmittedToSameLocation = isJsonFile &&
96                comparePaths(sourceFile.fileName, ownOutputFilePath, host.getCurrentDirectory(), !host.useCaseSensitiveFileNames()) === Comparison.EqualTo;
97            const jsFilePath = options.emitDeclarationOnly || isJsonEmittedToSameLocation ? undefined : ownOutputFilePath;
98            const sourceMapFilePath = !jsFilePath || isJsonSourceFile(sourceFile) ? undefined : getSourceMapFilePath(jsFilePath, options);
99            const declarationFilePath = (forceDtsPaths || (getEmitDeclarations(options) && !isJsonFile)) ? getDeclarationEmitOutputFilePath(sourceFile.fileName, host) : undefined;
100            const declarationMapPath = declarationFilePath && getAreDeclarationMapsEnabled(options) ? declarationFilePath + ".map" : undefined;
101            return { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, buildInfoPath: undefined };
102        }
103    }
104
105    function getSourceMapFilePath(jsFilePath: string, options: CompilerOptions) {
106        return (options.sourceMap && !options.inlineSourceMap) ? jsFilePath + ".map" : undefined;
107    }
108
109    /* @internal */
110    export function getOutputExtension(fileName: string, options: CompilerOptions): Extension {
111        return fileExtensionIs(fileName, Extension.Json) ? Extension.Json :
112        options.jsx === JsxEmit.Preserve && fileExtensionIsOneOf(fileName, [Extension.Jsx, Extension.Tsx]) ? Extension.Jsx :
113        fileExtensionIsOneOf(fileName, [Extension.Mts, Extension.Mjs]) ? Extension.Mjs :
114        fileExtensionIsOneOf(fileName, [Extension.Cts, Extension.Cjs]) ? Extension.Cjs :
115        Extension.Js;
116    }
117
118    function getOutputPathWithoutChangingExt(inputFileName: string, configFile: ParsedCommandLine, ignoreCase: boolean, outputDir: string | undefined, getCommonSourceDirectory?: () => string) {
119        return outputDir ?
120            resolvePath(
121                outputDir,
122                getRelativePathFromDirectory(getCommonSourceDirectory ? getCommonSourceDirectory() : getCommonSourceDirectoryOfConfig(configFile, ignoreCase), inputFileName, ignoreCase)
123            ) :
124            inputFileName;
125    }
126
127    /* @internal */
128    export function getOutputDeclarationFileName(inputFileName: string, configFile: ParsedCommandLine, ignoreCase: boolean, getCommonSourceDirectory?: () => string) {
129        return changeExtension(
130            getOutputPathWithoutChangingExt(inputFileName, configFile, ignoreCase, configFile.options.declarationDir || configFile.options.outDir, getCommonSourceDirectory),
131            getDeclarationEmitExtensionForPath(inputFileName)
132        );
133    }
134
135    function getOutputJSFileName(inputFileName: string, configFile: ParsedCommandLine, ignoreCase: boolean, getCommonSourceDirectory?: () => string) {
136        if (configFile.options.emitDeclarationOnly) return undefined;
137        const isJsonFile = fileExtensionIs(inputFileName, Extension.Json);
138        const outputFileName = changeExtension(
139            getOutputPathWithoutChangingExt(inputFileName, configFile, ignoreCase, configFile.options.outDir, getCommonSourceDirectory),
140            getOutputExtension(inputFileName, configFile.options)
141        );
142        return !isJsonFile || comparePaths(inputFileName, outputFileName, Debug.checkDefined(configFile.options.configFilePath), ignoreCase) !== Comparison.EqualTo ?
143            outputFileName :
144            undefined;
145    }
146
147    function createAddOutput() {
148        let outputs: string[] | undefined;
149        return { addOutput, getOutputs };
150        function addOutput(path: string | undefined) {
151            if (path) {
152                (outputs || (outputs = [])).push(path);
153            }
154        }
155        function getOutputs(): readonly string[] {
156            return outputs || emptyArray;
157        }
158    }
159
160    function getSingleOutputFileNames(configFile: ParsedCommandLine, addOutput: ReturnType<typeof createAddOutput>["addOutput"]) {
161        const { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, buildInfoPath } = getOutputPathsForBundle(configFile.options, /*forceDtsPaths*/ false);
162        addOutput(jsFilePath);
163        addOutput(sourceMapFilePath);
164        addOutput(declarationFilePath);
165        addOutput(declarationMapPath);
166        addOutput(buildInfoPath);
167    }
168
169    function getOwnOutputFileNames(configFile: ParsedCommandLine, inputFileName: string, ignoreCase: boolean, addOutput: ReturnType<typeof createAddOutput>["addOutput"], getCommonSourceDirectory?: () => string) {
170        if (isDeclarationFileName(inputFileName)) return;
171        const js = getOutputJSFileName(inputFileName, configFile, ignoreCase, getCommonSourceDirectory);
172        addOutput(js);
173        if (fileExtensionIs(inputFileName, Extension.Json)) return;
174        if (js && configFile.options.sourceMap) {
175            addOutput(`${js}.map`);
176        }
177        if (getEmitDeclarations(configFile.options)) {
178            const dts = getOutputDeclarationFileName(inputFileName, configFile, ignoreCase, getCommonSourceDirectory);
179            addOutput(dts);
180            if (configFile.options.declarationMap) {
181                addOutput(`${dts}.map`);
182            }
183        }
184    }
185
186    /*@internal*/
187    export function getCommonSourceDirectory(
188        options: CompilerOptions,
189        emittedFiles: () => readonly string[],
190        currentDirectory: string,
191        getCanonicalFileName: GetCanonicalFileName,
192        checkSourceFilesBelongToPath?: (commonSourceDirectory: string) => void
193    ): string {
194        let commonSourceDirectory;
195        if (options.rootDir) {
196            // If a rootDir is specified use it as the commonSourceDirectory
197            commonSourceDirectory = getNormalizedAbsolutePath(options.rootDir, currentDirectory);
198            checkSourceFilesBelongToPath?.(options.rootDir);
199        }
200        else if (options.composite && options.configFilePath) {
201            // Project compilations never infer their root from the input source paths
202            commonSourceDirectory = getDirectoryPath(normalizeSlashes(options.configFilePath));
203            checkSourceFilesBelongToPath?.(commonSourceDirectory);
204        }
205        else {
206            commonSourceDirectory = computeCommonSourceDirectoryOfFilenames(emittedFiles(), currentDirectory, getCanonicalFileName);
207        }
208
209        if (commonSourceDirectory && commonSourceDirectory[commonSourceDirectory.length - 1] !== directorySeparator) {
210            // Make sure directory path ends with directory separator so this string can directly
211            // used to replace with "" to get the relative path of the source file and the relative path doesn't
212            // start with / making it rooted path
213            commonSourceDirectory += directorySeparator;
214        }
215        return commonSourceDirectory;
216    }
217
218    /*@internal*/
219    export function getCommonSourceDirectoryOfConfig({ options, fileNames }: ParsedCommandLine, ignoreCase: boolean): string {
220        return getCommonSourceDirectory(
221            options,
222            () => filter(fileNames, file => !(options.noEmitForJsFiles && fileExtensionIsOneOf(file, supportedJSExtensionsFlat)) && !isDeclarationFileName(file)),
223            getDirectoryPath(normalizeSlashes(Debug.checkDefined(options.configFilePath))),
224            createGetCanonicalFileName(!ignoreCase)
225        );
226    }
227
228    /*@internal*/
229    export function getAllProjectOutputs(configFile: ParsedCommandLine, ignoreCase: boolean): readonly string[] {
230        const { addOutput, getOutputs } = createAddOutput();
231        if (outFile(configFile.options)) {
232            getSingleOutputFileNames(configFile, addOutput);
233        }
234        else {
235            const getCommonSourceDirectory = memoize(() => getCommonSourceDirectoryOfConfig(configFile, ignoreCase));
236            for (const inputFileName of configFile.fileNames) {
237                getOwnOutputFileNames(configFile, inputFileName, ignoreCase, addOutput, getCommonSourceDirectory);
238            }
239            addOutput(getTsBuildInfoEmitOutputFilePath(configFile.options));
240        }
241        return getOutputs();
242    }
243
244    export function getOutputFileNames(commandLine: ParsedCommandLine, inputFileName: string, ignoreCase: boolean): readonly string[] {
245        inputFileName = normalizePath(inputFileName);
246        Debug.assert(contains(commandLine.fileNames, inputFileName), `Expected fileName to be present in command line`);
247        const { addOutput, getOutputs } = createAddOutput();
248        if (outFile(commandLine.options)) {
249            getSingleOutputFileNames(commandLine, addOutput);
250        }
251        else {
252            getOwnOutputFileNames(commandLine, inputFileName, ignoreCase, addOutput);
253        }
254        return getOutputs();
255    }
256
257    /*@internal*/
258    export function getFirstProjectOutput(configFile: ParsedCommandLine, ignoreCase: boolean): string {
259        if (outFile(configFile.options)) {
260            const { jsFilePath } = getOutputPathsForBundle(configFile.options, /*forceDtsPaths*/ false);
261            return Debug.checkDefined(jsFilePath, `project ${configFile.options.configFilePath} expected to have at least one output`);
262        }
263
264        const getCommonSourceDirectory = memoize(() => getCommonSourceDirectoryOfConfig(configFile, ignoreCase));
265        for (const inputFileName of configFile.fileNames) {
266            if (isDeclarationFileName(inputFileName)) continue;
267            const jsFilePath = getOutputJSFileName(inputFileName, configFile, ignoreCase, getCommonSourceDirectory);
268            if (jsFilePath) return jsFilePath;
269            if (fileExtensionIs(inputFileName, Extension.Json)) continue;
270            if (getEmitDeclarations(configFile.options)) {
271                return getOutputDeclarationFileName(inputFileName, configFile, ignoreCase, getCommonSourceDirectory);
272            }
273        }
274        const buildInfoPath = getTsBuildInfoEmitOutputFilePath(configFile.options);
275        if (buildInfoPath) return buildInfoPath;
276        return Debug.fail(`project ${configFile.options.configFilePath} expected to have at least one output`);
277    }
278
279    /*@internal*/
280    // targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature
281    export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile | undefined, { scriptTransformers, declarationTransformers }: EmitTransformers, emitOnlyDtsFiles?: boolean, onlyBuildInfo?: boolean, forceDtsEmit?: boolean): EmitResult {
282        const compilerOptions = host.getCompilerOptions();
283        const sourceMapDataList: SourceMapEmitResult[] | undefined = (compilerOptions.sourceMap || compilerOptions.inlineSourceMap || getAreDeclarationMapsEnabled(compilerOptions)) ? [] : undefined;
284        const emittedFilesList: string[] | undefined = compilerOptions.listEmittedFiles ? [] : undefined;
285        const emitterDiagnostics = createDiagnosticCollection();
286        const newLine = getNewLineCharacter(compilerOptions, () => host.getNewLine());
287        const writer = createTextWriter(newLine);
288        const { enter, exit } = performance.createTimer("printTime", "beforePrint", "afterPrint");
289        let bundleBuildInfo: BundleBuildInfo | undefined;
290        let emitSkipped = false;
291
292        // Emit each output file
293        enter();
294        forEachEmittedFile(
295            host,
296            emitSourceFileOrBundle,
297            getSourceFilesToEmit(host, targetSourceFile, forceDtsEmit),
298            forceDtsEmit,
299            onlyBuildInfo,
300            !targetSourceFile
301        );
302        exit();
303
304
305        return {
306            emitSkipped,
307            diagnostics: emitterDiagnostics.getDiagnostics(),
308            emittedFiles: emittedFilesList,
309            sourceMaps: sourceMapDataList,
310        };
311
312        function emitSourceFileOrBundle({ jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, buildInfoPath }: EmitFileNames, sourceFileOrBundle: SourceFile | Bundle | undefined) {
313            let buildInfoDirectory: string | undefined;
314            if (buildInfoPath && sourceFileOrBundle && isBundle(sourceFileOrBundle)) {
315                buildInfoDirectory = getDirectoryPath(getNormalizedAbsolutePath(buildInfoPath, host.getCurrentDirectory()));
316                bundleBuildInfo = {
317                    commonSourceDirectory: relativeToBuildInfo(host.getCommonSourceDirectory()),
318                    sourceFiles: sourceFileOrBundle.sourceFiles.map(file => relativeToBuildInfo(getNormalizedAbsolutePath(file.fileName, host.getCurrentDirectory())))
319                };
320            }
321            tracing?.push(tracing.Phase.Emit, "emitJsFileOrBundle", { jsFilePath });
322            emitJsFileOrBundle(sourceFileOrBundle, jsFilePath, sourceMapFilePath, relativeToBuildInfo);
323            tracing?.pop();
324
325            tracing?.push(tracing.Phase.Emit, "emitDeclarationFileOrBundle", { declarationFilePath });
326            emitDeclarationFileOrBundle(sourceFileOrBundle, declarationFilePath, declarationMapPath, relativeToBuildInfo);
327            tracing?.pop();
328
329            tracing?.push(tracing.Phase.Emit, "emitBuildInfo", { buildInfoPath });
330            emitBuildInfo(bundleBuildInfo, buildInfoPath);
331            tracing?.pop();
332
333            if (!emitSkipped && emittedFilesList) {
334                if (!emitOnlyDtsFiles) {
335                    if (jsFilePath) {
336                        emittedFilesList.push(jsFilePath);
337                    }
338                    if (sourceMapFilePath) {
339                        emittedFilesList.push(sourceMapFilePath);
340                    }
341                    if (buildInfoPath) {
342                        emittedFilesList.push(buildInfoPath);
343                    }
344                }
345                if (declarationFilePath) {
346                    emittedFilesList.push(declarationFilePath);
347                }
348                if (declarationMapPath) {
349                    emittedFilesList.push(declarationMapPath);
350                }
351            }
352
353            function relativeToBuildInfo(path: string) {
354                return ensurePathIsNonModuleName(getRelativePathFromDirectory(buildInfoDirectory!, path, host.getCanonicalFileName));
355            }
356        }
357
358        function emitBuildInfo(bundle: BundleBuildInfo | undefined, buildInfoPath: string | undefined) {
359            // Write build information if applicable
360            if (!buildInfoPath || targetSourceFile || emitSkipped) return;
361            const program = host.getProgramBuildInfo();
362            if (host.isEmitBlocked(buildInfoPath)) {
363                emitSkipped = true;
364                return;
365            }
366            const version = ts.version; // Extracted into a const so the form is stable between namespace and module
367            const buildInfo: BuildInfo = { bundle, program, version };
368            // Pass buildinfo as additional data to avoid having to reparse
369            writeFile(host, emitterDiagnostics, buildInfoPath, getBuildInfoText(buildInfo), /*writeByteOrderMark*/ false, /*sourceFiles*/ undefined, { buildInfo });
370        }
371
372        function emitJsFileOrBundle(
373            sourceFileOrBundle: SourceFile | Bundle | undefined,
374            jsFilePath: string | undefined,
375            sourceMapFilePath: string | undefined,
376            relativeToBuildInfo: (path: string) => string) {
377            if (!sourceFileOrBundle || emitOnlyDtsFiles || !jsFilePath) {
378                return;
379            }
380
381            // Make sure not to write js file and source map file if any of them cannot be written
382            if (host.isEmitBlocked(jsFilePath) || compilerOptions.noEmit) {
383                emitSkipped = true;
384                return;
385            }
386            // Transform the source files
387            const transform = transformNodes(resolver, host, factory, compilerOptions, [sourceFileOrBundle], scriptTransformers, /*allowDtsFiles*/ false);
388
389            const printerOptions: PrinterOptions = {
390                removeComments: compilerOptions.removeComments,
391                newLine: compilerOptions.newLine,
392                noEmitHelpers: compilerOptions.noEmitHelpers,
393                module: compilerOptions.module,
394                target: compilerOptions.target,
395                sourceMap: compilerOptions.sourceMap,
396                inlineSourceMap: compilerOptions.inlineSourceMap,
397                inlineSources: compilerOptions.inlineSources,
398                extendedDiagnostics: compilerOptions.extendedDiagnostics,
399                writeBundleFileInfo: !!bundleBuildInfo,
400                relativeToBuildInfo
401            };
402
403            // Create a printer to print the nodes
404            const printer = createPrinter(printerOptions, {
405                // resolver hooks
406                hasGlobalName: resolver.hasGlobalName,
407
408                // transform hooks
409                onEmitNode: transform.emitNodeWithNotification,
410                isEmitNotificationEnabled: transform.isEmitNotificationEnabled,
411                substituteNode: transform.substituteNode,
412            });
413
414            Debug.assert(transform.transformed.length === 1, "Should only see one output from the transform");
415            printSourceFileOrBundle(jsFilePath, sourceMapFilePath, transform, printer, compilerOptions);
416
417            // Clean up emit nodes on parse tree
418            transform.dispose();
419            if (bundleBuildInfo) bundleBuildInfo.js = printer.bundleFileInfo;
420        }
421
422        function emitDeclarationFileOrBundle(
423            sourceFileOrBundle: SourceFile | Bundle | undefined,
424            declarationFilePath: string | undefined,
425            declarationMapPath: string | undefined,
426            relativeToBuildInfo: (path: string) => string) {
427            if (!sourceFileOrBundle) return;
428            if (!declarationFilePath) {
429                if (emitOnlyDtsFiles || compilerOptions.emitDeclarationOnly) emitSkipped = true;
430                return;
431            }
432            const sourceFiles = isSourceFile(sourceFileOrBundle) ? [sourceFileOrBundle] : sourceFileOrBundle.sourceFiles;
433            const filesForEmit = forceDtsEmit ? sourceFiles : filter(sourceFiles, isSourceFileNotJson);
434            // Setup and perform the transformation to retrieve declarations from the input files
435            const inputListOrBundle = outFile(compilerOptions) ? [factory.createBundle(filesForEmit, !isSourceFile(sourceFileOrBundle) ? sourceFileOrBundle.prepends : undefined)] : filesForEmit;
436            if (emitOnlyDtsFiles && !getEmitDeclarations(compilerOptions)) {
437                // Checker wont collect the linked aliases since thats only done when declaration is enabled.
438                // Do that here when emitting only dts files
439                filesForEmit.forEach(collectLinkedAliases);
440            }
441            const declarationTransform = transformNodes(resolver, host, factory, compilerOptions, inputListOrBundle, declarationTransformers, /*allowDtsFiles*/ false);
442            if (length(declarationTransform.diagnostics)) {
443                for (const diagnostic of declarationTransform.diagnostics!) {
444                    emitterDiagnostics.add(diagnostic);
445                }
446            }
447
448            const printerOptions: PrinterOptions = {
449                removeComments: compilerOptions.removeComments,
450                newLine: compilerOptions.newLine,
451                noEmitHelpers: true,
452                module: compilerOptions.module,
453                target: compilerOptions.target,
454                sourceMap: !forceDtsEmit && compilerOptions.declarationMap,
455                inlineSourceMap: compilerOptions.inlineSourceMap,
456                extendedDiagnostics: compilerOptions.extendedDiagnostics,
457                onlyPrintJsDocStyle: true,
458                writeBundleFileInfo: !!bundleBuildInfo,
459                recordInternalSection: !!bundleBuildInfo,
460                relativeToBuildInfo
461            };
462
463            const declarationPrinter = createPrinter(printerOptions, {
464                // resolver hooks
465                hasGlobalName: resolver.hasGlobalName,
466
467                // transform hooks
468                onEmitNode: declarationTransform.emitNodeWithNotification,
469                isEmitNotificationEnabled: declarationTransform.isEmitNotificationEnabled,
470                substituteNode: declarationTransform.substituteNode,
471            });
472            const declBlocked = (!!declarationTransform.diagnostics && !!declarationTransform.diagnostics.length) || !!host.isEmitBlocked(declarationFilePath) || !!compilerOptions.noEmit;
473            emitSkipped = emitSkipped || declBlocked;
474            if (!declBlocked || forceDtsEmit) {
475                Debug.assert(declarationTransform.transformed.length === 1, "Should only see one output from the decl transform");
476                printSourceFileOrBundle(
477                    declarationFilePath,
478                    declarationMapPath,
479                    declarationTransform,
480                    declarationPrinter,
481                    {
482                        sourceMap: printerOptions.sourceMap,
483                        sourceRoot: compilerOptions.sourceRoot,
484                        mapRoot: compilerOptions.mapRoot,
485                        extendedDiagnostics: compilerOptions.extendedDiagnostics,
486                        // Explicitly do not passthru either `inline` option
487                    }
488                );
489            }
490            declarationTransform.dispose();
491            if (bundleBuildInfo) bundleBuildInfo.dts = declarationPrinter.bundleFileInfo;
492        }
493
494        function collectLinkedAliases(node: Node) {
495            if (isExportAssignment(node)) {
496                if (node.expression.kind === SyntaxKind.Identifier) {
497                    resolver.collectLinkedAliases(node.expression as Identifier, /*setVisibility*/ true);
498                }
499                return;
500            }
501            else if (isExportSpecifier(node)) {
502                resolver.collectLinkedAliases(node.propertyName || node.name, /*setVisibility*/ true);
503                return;
504            }
505            forEachChild(node, collectLinkedAliases);
506        }
507
508        function printSourceFileOrBundle(jsFilePath: string, sourceMapFilePath: string | undefined, transform: TransformationResult<SourceFile | Bundle>, printer: Printer, mapOptions: SourceMapOptions) {
509            const sourceFileOrBundle = transform.transformed[0];
510            const bundle = sourceFileOrBundle.kind === SyntaxKind.Bundle ? sourceFileOrBundle : undefined;
511            const sourceFile = sourceFileOrBundle.kind === SyntaxKind.SourceFile ? sourceFileOrBundle : undefined;
512            const sourceFiles = bundle ? bundle.sourceFiles : [sourceFile!];
513
514            let sourceMapGenerator: SourceMapGenerator | undefined;
515            if (shouldEmitSourceMaps(mapOptions, sourceFileOrBundle)) {
516                sourceMapGenerator = createSourceMapGenerator(
517                    host,
518                    getBaseFileName(normalizeSlashes(jsFilePath)),
519                    getSourceRoot(mapOptions),
520                    getSourceMapDirectory(mapOptions, jsFilePath, sourceFile),
521                    mapOptions);
522            }
523
524            if (bundle) {
525                printer.writeBundle(bundle, writer, sourceMapGenerator);
526            }
527            else {
528                printer.writeFile(sourceFile!, writer, sourceMapGenerator);
529            }
530
531            let sourceMapUrlPos;
532            if (sourceMapGenerator) {
533                if (sourceMapDataList) {
534                    sourceMapDataList.push({
535                        inputSourceFileNames: sourceMapGenerator.getSources(),
536                        sourceMap: sourceMapGenerator.toJSON()
537                    });
538                }
539
540                const sourceMappingURL = getSourceMappingURL(
541                    mapOptions,
542                    sourceMapGenerator,
543                    jsFilePath,
544                    sourceMapFilePath,
545                    sourceFile);
546
547                if (sourceMappingURL) {
548                    if (!writer.isAtStartOfLine()) writer.rawWrite(newLine);
549                    sourceMapUrlPos = writer.getTextPos();
550                    writer.writeComment(`//# ${"sourceMappingURL"}=${sourceMappingURL}`); // Tools can sometimes see this line as a source mapping url comment
551                }
552
553                // Write the source map
554                if (sourceMapFilePath) {
555                    const sourceMap = sourceMapGenerator.toString();
556                    writeFile(host, emitterDiagnostics, sourceMapFilePath, sourceMap, /*writeByteOrderMark*/ false, sourceFiles);
557                    if (printer.bundleFileInfo) printer.bundleFileInfo.mapHash = computeSignature(sourceMap, maybeBind(host, host.createHash));
558                }
559            }
560            else {
561                writer.writeLine();
562            }
563
564            // Write the output file
565            const text = writer.getText();
566            writeFile(host, emitterDiagnostics, jsFilePath, text, !!compilerOptions.emitBOM, sourceFiles, { sourceMapUrlPos, diagnostics: transform.diagnostics });
567            // We store the hash of the text written in the buildinfo to ensure that text of the referenced d.ts file is same as whats in the buildinfo
568            // This is needed because incremental can be toggled between two runs and we might use stale file text to do text manipulation in prepend mode
569            if (printer.bundleFileInfo) printer.bundleFileInfo.hash = computeSignature(text, maybeBind(host, host.createHash));
570
571            // Reset state
572            writer.clear();
573        }
574
575        interface SourceMapOptions {
576            sourceMap?: boolean;
577            inlineSourceMap?: boolean;
578            inlineSources?: boolean;
579            sourceRoot?: string;
580            mapRoot?: string;
581            extendedDiagnostics?: boolean;
582        }
583
584        function shouldEmitSourceMaps(mapOptions: SourceMapOptions, sourceFileOrBundle: SourceFile | Bundle) {
585            return (mapOptions.sourceMap || mapOptions.inlineSourceMap)
586                && (sourceFileOrBundle.kind !== SyntaxKind.SourceFile || !fileExtensionIs(sourceFileOrBundle.fileName, Extension.Json));
587        }
588
589        function getSourceRoot(mapOptions: SourceMapOptions) {
590            // Normalize source root and make sure it has trailing "/" so that it can be used to combine paths with the
591            // relative paths of the sources list in the sourcemap
592            const sourceRoot = normalizeSlashes(mapOptions.sourceRoot || "");
593            return sourceRoot ? ensureTrailingDirectorySeparator(sourceRoot) : sourceRoot;
594        }
595
596        function getSourceMapDirectory(mapOptions: SourceMapOptions, filePath: string, sourceFile: SourceFile | undefined) {
597            if (mapOptions.sourceRoot) return host.getCommonSourceDirectory();
598            if (mapOptions.mapRoot) {
599                let sourceMapDir = normalizeSlashes(mapOptions.mapRoot);
600                if (sourceFile) {
601                    // For modules or multiple emit files the mapRoot will have directory structure like the sources
602                    // So if src\a.ts and src\lib\b.ts are compiled together user would be moving the maps into mapRoot\a.js.map and mapRoot\lib\b.js.map
603                    sourceMapDir = getDirectoryPath(getSourceFilePathInNewDir(sourceFile.fileName, host, sourceMapDir));
604                }
605                if (getRootLength(sourceMapDir) === 0) {
606                    // The relative paths are relative to the common directory
607                    sourceMapDir = combinePaths(host.getCommonSourceDirectory(), sourceMapDir);
608                }
609                return sourceMapDir;
610            }
611            return getDirectoryPath(normalizePath(filePath));
612        }
613
614        function getSourceMappingURL(mapOptions: SourceMapOptions, sourceMapGenerator: SourceMapGenerator, filePath: string, sourceMapFilePath: string | undefined, sourceFile: SourceFile | undefined) {
615            if (mapOptions.inlineSourceMap) {
616                // Encode the sourceMap into the sourceMap url
617                const sourceMapText = sourceMapGenerator.toString();
618                const base64SourceMapText = base64encode(sys, sourceMapText);
619                return `data:application/json;base64,${base64SourceMapText}`;
620            }
621
622            const sourceMapFile = getBaseFileName(normalizeSlashes(Debug.checkDefined(sourceMapFilePath)));
623            if (mapOptions.mapRoot) {
624                let sourceMapDir = normalizeSlashes(mapOptions.mapRoot);
625                if (sourceFile) {
626                    // For modules or multiple emit files the mapRoot will have directory structure like the sources
627                    // So if src\a.ts and src\lib\b.ts are compiled together user would be moving the maps into mapRoot\a.js.map and mapRoot\lib\b.js.map
628                    sourceMapDir = getDirectoryPath(getSourceFilePathInNewDir(sourceFile.fileName, host, sourceMapDir));
629                }
630                if (getRootLength(sourceMapDir) === 0) {
631                    // The relative paths are relative to the common directory
632                    sourceMapDir = combinePaths(host.getCommonSourceDirectory(), sourceMapDir);
633                    return encodeURI(
634                        getRelativePathToDirectoryOrUrl(
635                            getDirectoryPath(normalizePath(filePath)), // get the relative sourceMapDir path based on jsFilePath
636                            combinePaths(sourceMapDir, sourceMapFile), // this is where user expects to see sourceMap
637                            host.getCurrentDirectory(),
638                            host.getCanonicalFileName,
639                            /*isAbsolutePathAnUrl*/ true));
640                }
641                else {
642                    return encodeURI(combinePaths(sourceMapDir, sourceMapFile));
643                }
644            }
645            return encodeURI(sourceMapFile);
646        }
647    }
648
649    /*@internal*/
650    export function getBuildInfoText(buildInfo: BuildInfo) {
651        return JSON.stringify(buildInfo);
652    }
653
654    /*@internal*/
655    export function getBuildInfo(buildInfoFile: string, buildInfoText: string) {
656        return readJsonOrUndefined(buildInfoFile, buildInfoText) as BuildInfo | undefined;
657    }
658
659    /*@internal*/
660    export const notImplementedResolver: EmitResolver = {
661        hasGlobalName: notImplemented,
662        getReferencedExportContainer: notImplemented,
663        getReferencedImportDeclaration: notImplemented,
664        getReferencedDeclarationWithCollidingName: notImplemented,
665        isDeclarationWithCollidingName: notImplemented,
666        isValueAliasDeclaration: notImplemented,
667        isReferencedAliasDeclaration: notImplemented,
668        isReferenced: notImplemented,
669        isTopLevelValueImportEqualsWithEntityName: notImplemented,
670        getNodeCheckFlags: notImplemented,
671        isDeclarationVisible: notImplemented,
672        isLateBound: (_node): _node is LateBoundDeclaration => false,
673        collectLinkedAliases: notImplemented,
674        isImplementationOfOverload: notImplemented,
675        isRequiredInitializedParameter: notImplemented,
676        isOptionalUninitializedParameterProperty: notImplemented,
677        isExpandoFunctionDeclaration: notImplemented,
678        getPropertiesOfContainerFunction: notImplemented,
679        createTypeOfDeclaration: notImplemented,
680        createReturnTypeOfSignatureDeclaration: notImplemented,
681        createTypeOfExpression: notImplemented,
682        createLiteralConstValue: notImplemented,
683        isSymbolAccessible: notImplemented,
684        isEntityNameVisible: notImplemented,
685        // Returns the constant value this property access resolves to: notImplemented, or 'undefined' for a non-constant
686        getConstantValue: notImplemented,
687        getReferencedValueDeclaration: notImplemented,
688        getTypeReferenceSerializationKind: notImplemented,
689        isOptionalParameter: notImplemented,
690        moduleExportsSomeValue: notImplemented,
691        isArgumentsLocalBinding: notImplemented,
692        getExternalModuleFileFromDeclaration: notImplemented,
693        getTypeReferenceDirectivesForEntityName: notImplemented,
694        getTypeReferenceDirectivesForSymbol: notImplemented,
695        isLiteralConstDeclaration: notImplemented,
696        getJsxFactoryEntity: notImplemented,
697        getJsxFragmentFactoryEntity: notImplemented,
698        getAllAccessorDeclarations: notImplemented,
699        getSymbolOfExternalModuleSpecifier: notImplemented,
700        isBindingCapturedByNode: notImplemented,
701        getDeclarationStatementsForSourceFile: notImplemented,
702        isImportRequiredByAugmentation: notImplemented,
703    };
704
705    /*@internal*/
706    /** File that isnt present resulting in error or output files */
707    export type EmitUsingBuildInfoResult = string | readonly OutputFile[];
708
709    /*@internal*/
710    export interface EmitUsingBuildInfoHost extends ModuleResolutionHost {
711        getCurrentDirectory(): string;
712        getCanonicalFileName(fileName: string): string;
713        useCaseSensitiveFileNames(): boolean;
714        getNewLine(): string;
715        createHash?(data: string): string;
716        getBuildInfo?(fileName: string, configFilePath: string | undefined): BuildInfo | undefined;
717    }
718
719    function createSourceFilesFromBundleBuildInfo(bundle: BundleBuildInfo, buildInfoDirectory: string, host: EmitUsingBuildInfoHost): readonly SourceFile[] {
720        const jsBundle = Debug.checkDefined(bundle.js);
721        const prologueMap = jsBundle.sources?.prologues && arrayToMap(jsBundle.sources.prologues, prologueInfo => prologueInfo.file);
722        return bundle.sourceFiles.map((fileName, index) => {
723            const prologueInfo = prologueMap?.get(index);
724            const statements = prologueInfo?.directives.map(directive => {
725                const literal = setTextRange(factory.createStringLiteral(directive.expression.text), directive.expression);
726                const statement = setTextRange(factory.createExpressionStatement(literal), directive);
727                setParent(literal, statement);
728                return statement;
729            });
730            const eofToken = factory.createToken(SyntaxKind.EndOfFileToken);
731            const sourceFile = factory.createSourceFile(statements ?? [], eofToken, NodeFlags.None);
732            sourceFile.fileName = getRelativePathFromDirectory(
733                host.getCurrentDirectory(),
734                getNormalizedAbsolutePath(fileName, buildInfoDirectory),
735                !host.useCaseSensitiveFileNames()
736            );
737            sourceFile.text = prologueInfo?.text ?? "";
738            setTextRangePosWidth(sourceFile, 0, prologueInfo?.text.length ?? 0);
739            setEachParent(sourceFile.statements, sourceFile);
740            setTextRangePosWidth(eofToken, sourceFile.end, 0);
741            setParent(eofToken, sourceFile);
742            return sourceFile;
743        });
744    }
745
746    /*@internal*/
747    export function emitUsingBuildInfo(
748        config: ParsedCommandLine,
749        host: EmitUsingBuildInfoHost,
750        getCommandLine: (ref: ProjectReference) => ParsedCommandLine | undefined,
751        customTransformers?: CustomTransformers
752    ): EmitUsingBuildInfoResult {
753        const createHash = maybeBind(host, host.createHash);
754        const { buildInfoPath, jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath } = getOutputPathsForBundle(config.options, /*forceDtsPaths*/ false);
755        let buildInfo: BuildInfo | undefined;
756        if (host.getBuildInfo) {
757            // If host directly provides buildinfo we can get it directly. This allows host to cache the buildinfo
758            buildInfo = host.getBuildInfo(buildInfoPath!, config.options.configFilePath);
759        }
760        else {
761            const buildInfoText = host.readFile(buildInfoPath!);
762            if (!buildInfoText) return buildInfoPath!;
763            buildInfo = getBuildInfo(buildInfoPath!, buildInfoText);
764        }
765        if (!buildInfo) return buildInfoPath!;
766        if (!buildInfo.bundle || !buildInfo.bundle.js || (declarationFilePath && !buildInfo.bundle.dts)) return buildInfoPath!;
767
768        const jsFileText = host.readFile(Debug.checkDefined(jsFilePath));
769        if (!jsFileText) return jsFilePath!;
770        // If the jsFileText is not same has what it was created with, tsbuildinfo is stale so dont use it
771        if (computeSignature(jsFileText, createHash) !== buildInfo.bundle.js.hash) return jsFilePath!;
772        const sourceMapText = sourceMapFilePath && host.readFile(sourceMapFilePath);
773        // error if no source map or for now if inline sourcemap
774        if ((sourceMapFilePath && !sourceMapText) || config.options.inlineSourceMap) return sourceMapFilePath || "inline sourcemap decoding";
775        if (sourceMapFilePath && computeSignature(sourceMapText!, createHash) !== buildInfo.bundle.js.mapHash) return sourceMapFilePath;
776
777        // read declaration text
778        const declarationText = declarationFilePath && host.readFile(declarationFilePath);
779        if (declarationFilePath && !declarationText) return declarationFilePath;
780        if (declarationFilePath && computeSignature(declarationText!, createHash) !== buildInfo.bundle.dts!.hash) return declarationFilePath;
781        const declarationMapText = declarationMapPath && host.readFile(declarationMapPath);
782        // error if no source map or for now if inline sourcemap
783        if ((declarationMapPath && !declarationMapText) || config.options.inlineSourceMap) return declarationMapPath || "inline sourcemap decoding";
784        if (declarationMapPath && computeSignature(declarationMapText!, createHash) !== buildInfo.bundle.dts!.mapHash) return declarationMapPath;
785
786        const buildInfoDirectory = getDirectoryPath(getNormalizedAbsolutePath(buildInfoPath!, host.getCurrentDirectory()));
787        const ownPrependInput = createInputFiles(
788            jsFileText,
789            declarationText!,
790            sourceMapFilePath,
791            sourceMapText,
792            declarationMapPath,
793            declarationMapText,
794            jsFilePath,
795            declarationFilePath,
796            buildInfoPath,
797            buildInfo,
798            /*onlyOwnText*/ true
799        );
800        const outputFiles: OutputFile[] = [];
801        const prependNodes = createPrependNodes(config.projectReferences, getCommandLine, f => host.readFile(f));
802        const sourceFilesForJsEmit = createSourceFilesFromBundleBuildInfo(buildInfo.bundle, buildInfoDirectory, host);
803        let changedDtsText: string | undefined;
804        let changedDtsData: WriteFileCallbackData | undefined;
805        const emitHost: EmitHost = {
806            getPrependNodes: memoize(() => [...prependNodes, ownPrependInput]),
807            getCanonicalFileName: host.getCanonicalFileName,
808            getCommonSourceDirectory: () => getNormalizedAbsolutePath(buildInfo!.bundle!.commonSourceDirectory, buildInfoDirectory),
809            getCompilerOptions: () => config.options,
810            getCurrentDirectory: () => host.getCurrentDirectory(),
811            getNewLine: () => host.getNewLine(),
812            getSourceFile: returnUndefined,
813            getSourceFileByPath: returnUndefined,
814            getSourceFiles: () => sourceFilesForJsEmit,
815            getLibFileFromReference: notImplemented,
816            isSourceFileFromExternalLibrary: returnFalse,
817            getResolvedProjectReferenceToRedirect: returnUndefined,
818            getProjectReferenceRedirect: returnUndefined,
819            isSourceOfProjectReferenceRedirect: returnFalse,
820            writeFile: (name, text, writeByteOrderMark, _onError, _sourceFiles, data) => {
821                switch (name) {
822                    case jsFilePath:
823                        if (jsFileText === text) return;
824                        break;
825                    case sourceMapFilePath:
826                        if (sourceMapText === text) return;
827                        break;
828                    case buildInfoPath:
829                        const newBuildInfo = data!.buildInfo!;
830                        newBuildInfo.program = buildInfo!.program;
831                        if (newBuildInfo.program && changedDtsText !== undefined && config.options.composite) {
832                            // Update the output signature
833                            (newBuildInfo.program as ProgramBundleEmitBuildInfo).outSignature = computeSignature(changedDtsText, createHash, changedDtsData);
834                        }
835                        // Update sourceFileInfo
836                        const { js, dts, sourceFiles } = buildInfo!.bundle!;
837                        newBuildInfo.bundle!.js!.sources = js!.sources;
838                        if (dts) {
839                            newBuildInfo.bundle!.dts!.sources = dts.sources;
840                        }
841                        newBuildInfo.bundle!.sourceFiles = sourceFiles;
842                        outputFiles.push({ name, text: getBuildInfoText(newBuildInfo), writeByteOrderMark, buildInfo: newBuildInfo });
843                        return;
844                    case declarationFilePath:
845                        if (declarationText === text) return;
846                        changedDtsText = text;
847                        changedDtsData = data;
848                        break;
849                    case declarationMapPath:
850                        if (declarationMapText === text) return;
851                        break;
852                    default:
853                        Debug.fail(`Unexpected path: ${name}`);
854                }
855                outputFiles.push({ name, text, writeByteOrderMark });
856            },
857            isEmitBlocked: returnFalse,
858            readFile: f => host.readFile(f),
859            fileExists: f => host.fileExists(f),
860            useCaseSensitiveFileNames: () => host.useCaseSensitiveFileNames(),
861            getProgramBuildInfo: returnUndefined,
862            getSourceFileFromReference: returnUndefined,
863            redirectTargetsMap: createMultiMap(),
864            getFileIncludeReasons: notImplemented,
865            createHash,
866        };
867        emitFiles(
868            notImplementedResolver,
869            emitHost,
870            /*targetSourceFile*/ undefined,
871            getTransformers(config.options, customTransformers)
872        );
873        return outputFiles;
874    }
875
876    const enum PipelinePhase {
877        Notification,
878        Substitution,
879        Comments,
880        SourceMaps,
881        Emit,
882    }
883
884    export function createPrinter(printerOptions: PrinterOptions = {}, handlers: PrintHandlers = {}): Printer {
885        const {
886            hasGlobalName,
887            onEmitNode = noEmitNotification,
888            isEmitNotificationEnabled,
889            substituteNode = noEmitSubstitution,
890            onBeforeEmitNode,
891            onAfterEmitNode,
892            onBeforeEmitNodeArray,
893            onAfterEmitNodeArray,
894            onBeforeEmitToken,
895            onAfterEmitToken
896        } = handlers;
897
898        const extendedDiagnostics = !!printerOptions.extendedDiagnostics;
899        const newLine = getNewLineCharacter(printerOptions);
900        const moduleKind = getEmitModuleKind(printerOptions);
901        const bundledHelpers = new Map<string, boolean>();
902        let removeCommentsCollection: string[] | undefined;
903
904        let currentSourceFile: SourceFile | undefined;
905        let nodeIdToGeneratedName: string[]; // Map of generated names for specific nodes.
906        let autoGeneratedIdToGeneratedName: string[]; // Map of generated names for temp and loop variables.
907        let generatedNames: Set<string>; // Set of names generated by the NameGenerator.
908        let formattedNameTempFlagsStack: (ESMap<string, TempFlags> | undefined)[];
909        let formattedNameTempFlags: ESMap<string, TempFlags> | undefined;
910        let privateNameTempFlagsStack: TempFlags[]; // Stack of enclosing name generation scopes.
911        let privateNameTempFlags: TempFlags; // TempFlags for the current name generation scope.
912        let tempFlagsStack: TempFlags[]; // Stack of enclosing name generation scopes.
913        let tempFlags: TempFlags; // TempFlags for the current name generation scope.
914        let reservedNamesStack: Set<string>[]; // Stack of TempFlags reserved in enclosing name generation scopes.
915        let reservedNames: Set<string>; // TempFlags to reserve in nested name generation scopes.
916        let preserveSourceNewlines = printerOptions.preserveSourceNewlines; // Can be overridden inside nodes with the `IgnoreSourceNewlines` emit flag.
917        let nextListElementPos: number | undefined; // See comment in `getLeadingLineTerminatorCount`.
918
919        let writer: EmitTextWriter;
920        let ownWriter: EmitTextWriter; // Reusable `EmitTextWriter` for basic printing.
921        let write = writeBase;
922        let isOwnFileEmit: boolean;
923        const bundleFileInfo = printerOptions.writeBundleFileInfo ? { sections: [] } as BundleFileInfo : undefined;
924        const relativeToBuildInfo = bundleFileInfo ? Debug.checkDefined(printerOptions.relativeToBuildInfo) : undefined;
925        const recordInternalSection = printerOptions.recordInternalSection;
926        let sourceFileTextPos = 0;
927        let sourceFileTextKind: BundleFileTextLikeKind = BundleFileSectionKind.Text;
928
929        // Source Maps
930        let sourceMapsDisabled = true;
931        let sourceMapGenerator: SourceMapGenerator | undefined;
932        let sourceMapSource: SourceMapSource;
933        let sourceMapSourceIndex = -1;
934        let mostRecentlyAddedSourceMapSource: SourceMapSource;
935        let mostRecentlyAddedSourceMapSourceIndex = -1;
936
937        // Comments
938        let containerPos = -1;
939        let containerEnd = -1;
940        let declarationListContainerEnd = -1;
941        let currentLineMap: readonly number[] | undefined;
942        let detachedCommentsInfo: { nodePos: number, detachedCommentEndPos: number }[] | undefined;
943        let hasWrittenComment = false;
944        let commentsDisabled = !!printerOptions.removeComments;
945        let lastSubstitution: Node | undefined;
946        let currentParenthesizerRule: ((node: Node) => Node) | undefined;
947        const { enter: enterComment, exit: exitComment } = performance.createTimerIf(extendedDiagnostics, "commentTime", "beforeComment", "afterComment");
948        const parenthesizer = factory.parenthesizer;
949        const typeArgumentParenthesizerRuleSelector: OrdinalParentheizerRuleSelector<Node> = {
950            select: index => index === 0 ? parenthesizer.parenthesizeLeadingTypeArgument : undefined
951        };
952        const emitBinaryExpression = createEmitBinaryExpression();
953
954        reset();
955        return {
956            // public API
957            printNode,
958            printList,
959            printFile,
960            printBundle,
961
962            // internal API
963            writeNode,
964            writeList,
965            writeFile,
966            writeBundle,
967            bundleFileInfo
968        };
969
970        function printNode(hint: EmitHint, node: Node, sourceFile: SourceFile): string {
971            switch (hint) {
972                case EmitHint.SourceFile:
973                    Debug.assert(isSourceFile(node), "Expected a SourceFile node.");
974                    break;
975                case EmitHint.IdentifierName:
976                    Debug.assert(isIdentifier(node), "Expected an Identifier node.");
977                    break;
978                case EmitHint.Expression:
979                    Debug.assert(isExpression(node), "Expected an Expression node.");
980                    break;
981            }
982            switch (node.kind) {
983                case SyntaxKind.SourceFile: return printFile(node as SourceFile);
984                case SyntaxKind.Bundle: return printBundle(node as Bundle);
985                case SyntaxKind.UnparsedSource: return printUnparsedSource(node as UnparsedSource);
986            }
987            writeNode(hint, node, sourceFile, beginPrint());
988            return endPrint();
989        }
990
991        function printList<T extends Node>(format: ListFormat, nodes: NodeArray<T>, sourceFile: SourceFile) {
992            writeList(format, nodes, sourceFile, beginPrint());
993            return endPrint();
994        }
995
996        function printBundle(bundle: Bundle): string {
997            writeBundle(bundle, beginPrint(), /*sourceMapEmitter*/ undefined);
998            return endPrint();
999        }
1000
1001        function printFile(sourceFile: SourceFile): string {
1002            writeFile(sourceFile, beginPrint(), /*sourceMapEmitter*/ undefined);
1003            return endPrint();
1004        }
1005
1006        function printUnparsedSource(unparsed: UnparsedSource): string {
1007            writeUnparsedSource(unparsed, beginPrint());
1008            return endPrint();
1009        }
1010
1011        /**
1012         * If `sourceFile` is `undefined`, `node` must be a synthesized `TypeNode`.
1013         */
1014        function writeNode(hint: EmitHint, node: TypeNode, sourceFile: undefined, output: EmitTextWriter): void;
1015        function writeNode(hint: EmitHint, node: Node, sourceFile: SourceFile, output: EmitTextWriter): void;
1016        function writeNode(hint: EmitHint, node: Node, sourceFile: SourceFile | undefined, output: EmitTextWriter) {
1017            const previousWriter = writer;
1018            setWriter(output, /*_sourceMapGenerator*/ undefined);
1019            print(hint, node, sourceFile);
1020            reset();
1021            writer = previousWriter;
1022        }
1023
1024        function writeList<T extends Node>(format: ListFormat, nodes: NodeArray<T>, sourceFile: SourceFile | undefined, output: EmitTextWriter) {
1025            const previousWriter = writer;
1026            setWriter(output, /*_sourceMapGenerator*/ undefined);
1027            if (sourceFile) {
1028                setSourceFile(sourceFile);
1029            }
1030            emitList(/*parentNode*/ undefined, nodes, format);
1031            reset();
1032            writer = previousWriter;
1033        }
1034
1035        function getTextPosWithWriteLine() {
1036            return writer.getTextPosWithWriteLine ? writer.getTextPosWithWriteLine() : writer.getTextPos();
1037        }
1038
1039        function updateOrPushBundleFileTextLike(pos: number, end: number, kind: BundleFileTextLikeKind) {
1040            const last = lastOrUndefined(bundleFileInfo!.sections);
1041            if (last && last.kind === kind) {
1042                last.end = end;
1043            }
1044            else {
1045                bundleFileInfo!.sections.push({ pos, end, kind });
1046            }
1047        }
1048
1049        function recordBundleFileInternalSectionStart(node: Node) {
1050            if (recordInternalSection &&
1051                bundleFileInfo &&
1052                currentSourceFile &&
1053                (isDeclaration(node) || isVariableStatement(node)) &&
1054                isInternalDeclaration(node, currentSourceFile) &&
1055                sourceFileTextKind !== BundleFileSectionKind.Internal) {
1056                const prevSourceFileTextKind = sourceFileTextKind;
1057                recordBundleFileTextLikeSection(writer.getTextPos());
1058                sourceFileTextPos = getTextPosWithWriteLine();
1059                sourceFileTextKind = BundleFileSectionKind.Internal;
1060                return prevSourceFileTextKind;
1061            }
1062            return undefined;
1063        }
1064
1065        function recordBundleFileInternalSectionEnd(prevSourceFileTextKind: ReturnType<typeof recordBundleFileInternalSectionStart>) {
1066            if (prevSourceFileTextKind) {
1067                recordBundleFileTextLikeSection(writer.getTextPos());
1068                sourceFileTextPos = getTextPosWithWriteLine();
1069                sourceFileTextKind = prevSourceFileTextKind;
1070            }
1071        }
1072
1073        function recordBundleFileTextLikeSection(end: number) {
1074            if (sourceFileTextPos < end) {
1075                updateOrPushBundleFileTextLike(sourceFileTextPos, end, sourceFileTextKind);
1076                return true;
1077            }
1078            return false;
1079        }
1080
1081        function writeBundle(bundle: Bundle, output: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined) {
1082            isOwnFileEmit = false;
1083            const previousWriter = writer;
1084            setWriter(output, sourceMapGenerator);
1085            emitShebangIfNeeded(bundle);
1086            emitPrologueDirectivesIfNeeded(bundle);
1087            emitHelpers(bundle);
1088            emitSyntheticTripleSlashReferencesIfNeeded(bundle);
1089
1090            for (const prepend of bundle.prepends) {
1091                writeLine();
1092                const pos = writer.getTextPos();
1093                const savedSections = bundleFileInfo && bundleFileInfo.sections;
1094                if (savedSections) bundleFileInfo.sections = [];
1095                print(EmitHint.Unspecified, prepend, /*sourceFile*/ undefined);
1096                if (bundleFileInfo) {
1097                    const newSections = bundleFileInfo.sections;
1098                    bundleFileInfo.sections = savedSections!;
1099                    if (prepend.oldFileOfCurrentEmit) bundleFileInfo.sections.push(...newSections);
1100                    else {
1101                        newSections.forEach(section => Debug.assert(isBundleFileTextLike(section)));
1102                        bundleFileInfo.sections.push({
1103                            pos,
1104                            end: writer.getTextPos(),
1105                            kind: BundleFileSectionKind.Prepend,
1106                            data: relativeToBuildInfo!((prepend as UnparsedSource).fileName),
1107                            texts: newSections as BundleFileTextLike[]
1108                        });
1109                    }
1110                }
1111            }
1112
1113            sourceFileTextPos = getTextPosWithWriteLine();
1114            for (const sourceFile of bundle.sourceFiles) {
1115                print(EmitHint.SourceFile, sourceFile, sourceFile);
1116            }
1117            if (bundleFileInfo && bundle.sourceFiles.length) {
1118                const end = writer.getTextPos();
1119                if (recordBundleFileTextLikeSection(end)) {
1120                    // Store prologues
1121                    const prologues = getPrologueDirectivesFromBundledSourceFiles(bundle);
1122                    if (prologues) {
1123                        if (!bundleFileInfo.sources) bundleFileInfo.sources = {};
1124                        bundleFileInfo.sources.prologues = prologues;
1125                    }
1126
1127                    // Store helpes
1128                    const helpers = getHelpersFromBundledSourceFiles(bundle);
1129                    if (helpers) {
1130                        if (!bundleFileInfo.sources) bundleFileInfo.sources = {};
1131                        bundleFileInfo.sources.helpers = helpers;
1132                    }
1133                }
1134            }
1135
1136            reset();
1137            writer = previousWriter;
1138        }
1139
1140        function writeUnparsedSource(unparsed: UnparsedSource, output: EmitTextWriter) {
1141            const previousWriter = writer;
1142            setWriter(output, /*_sourceMapGenerator*/ undefined);
1143            print(EmitHint.Unspecified, unparsed, /*sourceFile*/ undefined);
1144            reset();
1145            writer = previousWriter;
1146        }
1147
1148        function writeFile(sourceFile: SourceFile, output: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined) {
1149            //@ts-ignore
1150            removeCommentsCollection = sourceFile?.reservedComments;
1151            isOwnFileEmit = true;
1152            const previousWriter = writer;
1153            setWriter(output, sourceMapGenerator);
1154            emitShebangIfNeeded(sourceFile);
1155            emitPrologueDirectivesIfNeeded(sourceFile);
1156            print(EmitHint.SourceFile, sourceFile, sourceFile);
1157            reset();
1158            writer = previousWriter;
1159        }
1160
1161        function beginPrint() {
1162            return ownWriter || (ownWriter = createTextWriter(newLine));
1163        }
1164
1165        function endPrint() {
1166            const text = ownWriter.getText();
1167            ownWriter.clear();
1168            return text;
1169        }
1170
1171        function print(hint: EmitHint, node: Node, sourceFile: SourceFile | undefined) {
1172            if (sourceFile) {
1173                setSourceFile(sourceFile);
1174            }
1175
1176            pipelineEmit(hint, node, /*parenthesizerRule*/ undefined);
1177        }
1178
1179        function setSourceFile(sourceFile: SourceFile | undefined) {
1180            currentSourceFile = sourceFile;
1181            currentLineMap = undefined;
1182            detachedCommentsInfo = undefined;
1183            if (sourceFile) {
1184                setSourceMapSource(sourceFile);
1185            }
1186        }
1187
1188        function setWriter(_writer: EmitTextWriter | undefined, _sourceMapGenerator: SourceMapGenerator | undefined) {
1189            if (_writer && printerOptions.omitTrailingSemicolon) {
1190                _writer = getTrailingSemicolonDeferringWriter(_writer);
1191            }
1192
1193            writer = _writer!; // TODO: GH#18217
1194            sourceMapGenerator = _sourceMapGenerator;
1195            sourceMapsDisabled = !writer || !sourceMapGenerator;
1196        }
1197
1198        function reset() {
1199            nodeIdToGeneratedName = [];
1200            autoGeneratedIdToGeneratedName = [];
1201            generatedNames = new Set();
1202            formattedNameTempFlagsStack = [];
1203            formattedNameTempFlags = new Map();
1204            privateNameTempFlagsStack = [];
1205            privateNameTempFlags = TempFlags.Auto;
1206            tempFlagsStack = [];
1207            tempFlags = TempFlags.Auto;
1208            reservedNamesStack = [];
1209            currentSourceFile = undefined;
1210            currentLineMap = undefined;
1211            detachedCommentsInfo = undefined;
1212            setWriter(/*output*/ undefined, /*_sourceMapGenerator*/ undefined);
1213        }
1214
1215        function getCurrentLineMap() {
1216            return currentLineMap || (currentLineMap = getLineStarts(Debug.checkDefined(currentSourceFile)));
1217        }
1218
1219        function emit(node: Node, parenthesizerRule?: (node: Node) => Node): void;
1220        function emit(node: Node | undefined, parenthesizerRule?: (node: Node) => Node): void;
1221        function emit(node: Node | undefined, parenthesizerRule?: (node: Node) => Node) {
1222            if (node === undefined) return;
1223            const prevSourceFileTextKind = recordBundleFileInternalSectionStart(node);
1224            pipelineEmit(EmitHint.Unspecified, node, parenthesizerRule);
1225            recordBundleFileInternalSectionEnd(prevSourceFileTextKind);
1226        }
1227
1228        function emitIdentifierName(node: Identifier): void;
1229        function emitIdentifierName(node: Identifier | undefined): void;
1230        function emitIdentifierName(node: Identifier | undefined) {
1231            if (node === undefined) return;
1232            pipelineEmit(EmitHint.IdentifierName, node, /*parenthesizerRule*/ undefined);
1233        }
1234
1235        function emitExpression(node: Expression, parenthesizerRule?: (node: Expression) => Expression): void;
1236        function emitExpression(node: Expression | undefined, parenthesizerRule?: (node: Expression) => Expression): void;
1237        function emitExpression(node: Expression | undefined, parenthesizerRule?: (node: Expression) => Expression) {
1238            if (node === undefined) return;
1239            pipelineEmit(EmitHint.Expression, node, parenthesizerRule);
1240        }
1241
1242        function emitJsxAttributeValue(node: StringLiteral | JsxExpression): void {
1243            pipelineEmit(isStringLiteral(node) ? EmitHint.JsxAttributeValue : EmitHint.Unspecified, node);
1244        }
1245
1246        function beforeEmitNode(node: Node) {
1247            if (preserveSourceNewlines && (getEmitFlags(node) & EmitFlags.IgnoreSourceNewlines)) {
1248                preserveSourceNewlines = false;
1249            }
1250        }
1251
1252        function afterEmitNode(savedPreserveSourceNewlines: boolean | undefined) {
1253            preserveSourceNewlines = savedPreserveSourceNewlines;
1254        }
1255
1256        function pipelineEmit(emitHint: EmitHint, node: Node, parenthesizerRule?: (node: Node) => Node) {
1257            currentParenthesizerRule = parenthesizerRule;
1258            const pipelinePhase = getPipelinePhase(PipelinePhase.Notification, emitHint, node);
1259            pipelinePhase(emitHint, node);
1260            currentParenthesizerRule = undefined;
1261        }
1262
1263        function shouldEmitComments(node: Node) {
1264            return !commentsDisabled && !isSourceFile(node);
1265        }
1266
1267        function shouldEmitSourceMaps(node: Node) {
1268            return !sourceMapsDisabled &&
1269                !isSourceFile(node) &&
1270                !isInJsonFile(node) &&
1271                !isUnparsedSource(node) &&
1272                !isUnparsedPrepend(node);
1273        }
1274
1275        function getPipelinePhase(phase: PipelinePhase, emitHint: EmitHint, node: Node) {
1276            switch (phase) {
1277                case PipelinePhase.Notification:
1278                    if (onEmitNode !== noEmitNotification && (!isEmitNotificationEnabled || isEmitNotificationEnabled(node))) {
1279                        return pipelineEmitWithNotification;
1280                    }
1281                    // falls through
1282                case PipelinePhase.Substitution:
1283                    if (substituteNode !== noEmitSubstitution && (lastSubstitution = substituteNode(emitHint, node) || node) !== node) {
1284                        if (currentParenthesizerRule) {
1285                            lastSubstitution = currentParenthesizerRule(lastSubstitution);
1286                        }
1287                        return pipelineEmitWithSubstitution;
1288                    }
1289                    // falls through
1290                case PipelinePhase.Comments:
1291                    if (shouldEmitComments(node)) {
1292                        return pipelineEmitWithComments;
1293                    }
1294                    // falls through
1295                case PipelinePhase.SourceMaps:
1296                    if (shouldEmitSourceMaps(node)) {
1297                        return pipelineEmitWithSourceMaps;
1298                    }
1299                    // falls through
1300                case PipelinePhase.Emit:
1301                    return pipelineEmitWithHint;
1302                default:
1303                    return Debug.assertNever(phase);
1304            }
1305        }
1306
1307        function getNextPipelinePhase(currentPhase: PipelinePhase, emitHint: EmitHint, node: Node) {
1308            return getPipelinePhase(currentPhase + 1, emitHint, node);
1309        }
1310
1311        function pipelineEmitWithNotification(hint: EmitHint, node: Node) {
1312            const pipelinePhase = getNextPipelinePhase(PipelinePhase.Notification, hint, node);
1313            onEmitNode(hint, node, pipelinePhase);
1314        }
1315
1316        function pipelineEmitWithHint(hint: EmitHint, node: Node): void {
1317            onBeforeEmitNode?.(node);
1318            if (preserveSourceNewlines) {
1319                const savedPreserveSourceNewlines = preserveSourceNewlines;
1320                beforeEmitNode(node);
1321                pipelineEmitWithHintWorker(hint, node);
1322                afterEmitNode(savedPreserveSourceNewlines);
1323            }
1324            else {
1325                pipelineEmitWithHintWorker(hint, node);
1326            }
1327            onAfterEmitNode?.(node);
1328            // clear the parenthesizer rule as we ascend
1329            currentParenthesizerRule = undefined;
1330        }
1331
1332        function pipelineEmitWithHintWorker(hint: EmitHint, node: Node, allowSnippets = true): void {
1333            if (allowSnippets) {
1334                const snippet = getSnippetElement(node);
1335                if (snippet) {
1336                    return emitSnippetNode(hint, node, snippet);
1337                }
1338            }
1339            if (hint === EmitHint.SourceFile) return emitSourceFile(cast(node, isSourceFile));
1340            if (hint === EmitHint.IdentifierName) return emitIdentifier(cast(node, isIdentifier));
1341            if (hint === EmitHint.JsxAttributeValue) return emitLiteral(cast(node, isStringLiteral), /*jsxAttributeEscape*/ true);
1342            if (hint === EmitHint.MappedTypeParameter) return emitMappedTypeParameter(cast(node, isTypeParameterDeclaration));
1343            if (hint === EmitHint.EmbeddedStatement) {
1344                Debug.assertNode(node, isEmptyStatement);
1345                return emitEmptyStatement(/*isEmbeddedStatement*/ true);
1346            }
1347            if (hint === EmitHint.Unspecified) {
1348                switch (node.kind) {
1349                    // Pseudo-literals
1350                    case SyntaxKind.TemplateHead:
1351                    case SyntaxKind.TemplateMiddle:
1352                    case SyntaxKind.TemplateTail:
1353                        return emitLiteral(node as LiteralExpression, /*jsxAttributeEscape*/ false);
1354
1355                    // Identifiers
1356                    case SyntaxKind.Identifier:
1357                        return emitIdentifier(node as Identifier);
1358
1359                    // PrivateIdentifiers
1360                    case SyntaxKind.PrivateIdentifier:
1361                        return emitPrivateIdentifier(node as PrivateIdentifier);
1362
1363                    // Parse tree nodes
1364                    // Names
1365                    case SyntaxKind.QualifiedName:
1366                        return emitQualifiedName(node as QualifiedName);
1367                    case SyntaxKind.ComputedPropertyName:
1368                        return emitComputedPropertyName(node as ComputedPropertyName);
1369
1370                    // Signature elements
1371                    case SyntaxKind.TypeParameter:
1372                        return emitTypeParameter(node as TypeParameterDeclaration);
1373                    case SyntaxKind.Parameter:
1374                        return emitParameter(node as ParameterDeclaration);
1375                    case SyntaxKind.Decorator:
1376                        return emitDecorator(node as Decorator);
1377
1378                    // Type members
1379                    case SyntaxKind.PropertySignature:
1380                        return emitPropertySignature(node as PropertySignature);
1381                    case SyntaxKind.PropertyDeclaration:
1382                        return emitPropertyDeclaration(node as PropertyDeclaration);
1383                    case SyntaxKind.MethodSignature:
1384                        return emitMethodSignature(node as MethodSignature);
1385                    case SyntaxKind.MethodDeclaration:
1386                        return emitMethodDeclaration(node as MethodDeclaration);
1387                    case SyntaxKind.ClassStaticBlockDeclaration:
1388                        return emitClassStaticBlockDeclaration(node as ClassStaticBlockDeclaration);
1389                    case SyntaxKind.Constructor:
1390                        return emitConstructor(node as ConstructorDeclaration);
1391                    case SyntaxKind.GetAccessor:
1392                    case SyntaxKind.SetAccessor:
1393                        return emitAccessorDeclaration(node as AccessorDeclaration);
1394                    case SyntaxKind.CallSignature:
1395                        return emitCallSignature(node as CallSignatureDeclaration);
1396                    case SyntaxKind.ConstructSignature:
1397                        return emitConstructSignature(node as ConstructSignatureDeclaration);
1398                    case SyntaxKind.IndexSignature:
1399                        return emitIndexSignature(node as IndexSignatureDeclaration);
1400
1401                    // Types
1402                    case SyntaxKind.TypePredicate:
1403                        return emitTypePredicate(node as TypePredicateNode);
1404                    case SyntaxKind.TypeReference:
1405                        return emitTypeReference(node as TypeReferenceNode);
1406                    case SyntaxKind.FunctionType:
1407                        return emitFunctionType(node as FunctionTypeNode);
1408                    case SyntaxKind.ConstructorType:
1409                        return emitConstructorType(node as ConstructorTypeNode);
1410                    case SyntaxKind.TypeQuery:
1411                        return emitTypeQuery(node as TypeQueryNode);
1412                    case SyntaxKind.TypeLiteral:
1413                        return emitTypeLiteral(node as TypeLiteralNode);
1414                    case SyntaxKind.ArrayType:
1415                        return emitArrayType(node as ArrayTypeNode);
1416                    case SyntaxKind.TupleType:
1417                        return emitTupleType(node as TupleTypeNode);
1418                    case SyntaxKind.OptionalType:
1419                        return emitOptionalType(node as OptionalTypeNode);
1420                    // SyntaxKind.RestType is handled below
1421                    case SyntaxKind.UnionType:
1422                        return emitUnionType(node as UnionTypeNode);
1423                    case SyntaxKind.IntersectionType:
1424                        return emitIntersectionType(node as IntersectionTypeNode);
1425                    case SyntaxKind.ConditionalType:
1426                        return emitConditionalType(node as ConditionalTypeNode);
1427                    case SyntaxKind.InferType:
1428                        return emitInferType(node as InferTypeNode);
1429                    case SyntaxKind.ParenthesizedType:
1430                        return emitParenthesizedType(node as ParenthesizedTypeNode);
1431                    case SyntaxKind.ExpressionWithTypeArguments:
1432                        return emitExpressionWithTypeArguments(node as ExpressionWithTypeArguments);
1433                    case SyntaxKind.ThisType:
1434                        return emitThisType();
1435                    case SyntaxKind.TypeOperator:
1436                        return emitTypeOperator(node as TypeOperatorNode);
1437                    case SyntaxKind.IndexedAccessType:
1438                        return emitIndexedAccessType(node as IndexedAccessTypeNode);
1439                    case SyntaxKind.MappedType:
1440                        return emitMappedType(node as MappedTypeNode);
1441                    case SyntaxKind.LiteralType:
1442                        return emitLiteralType(node as LiteralTypeNode);
1443                    case SyntaxKind.NamedTupleMember:
1444                        return emitNamedTupleMember(node as NamedTupleMember);
1445                    case SyntaxKind.TemplateLiteralType:
1446                        return emitTemplateType(node as TemplateLiteralTypeNode);
1447                    case SyntaxKind.TemplateLiteralTypeSpan:
1448                        return emitTemplateTypeSpan(node as TemplateLiteralTypeSpan);
1449                    case SyntaxKind.ImportType:
1450                        return emitImportTypeNode(node as ImportTypeNode);
1451
1452                    // Binding patterns
1453                    case SyntaxKind.ObjectBindingPattern:
1454                        return emitObjectBindingPattern(node as ObjectBindingPattern);
1455                    case SyntaxKind.ArrayBindingPattern:
1456                        return emitArrayBindingPattern(node as ArrayBindingPattern);
1457                    case SyntaxKind.BindingElement:
1458                        return emitBindingElement(node as BindingElement);
1459
1460                    // Misc
1461                    case SyntaxKind.TemplateSpan:
1462                        return emitTemplateSpan(node as TemplateSpan);
1463                    case SyntaxKind.SemicolonClassElement:
1464                        return emitSemicolonClassElement();
1465
1466                    // Statements
1467                    case SyntaxKind.Block:
1468                        return emitBlock(node as Block);
1469                    case SyntaxKind.VariableStatement:
1470                        return emitVariableStatement(node as VariableStatement);
1471                    case SyntaxKind.EmptyStatement:
1472                        return emitEmptyStatement(/*isEmbeddedStatement*/ false);
1473                    case SyntaxKind.ExpressionStatement:
1474                        return emitExpressionStatement(node as ExpressionStatement);
1475                    case SyntaxKind.IfStatement:
1476                        return emitIfStatement(node as IfStatement);
1477                    case SyntaxKind.DoStatement:
1478                        return emitDoStatement(node as DoStatement);
1479                    case SyntaxKind.WhileStatement:
1480                        return emitWhileStatement(node as WhileStatement);
1481                    case SyntaxKind.ForStatement:
1482                        return emitForStatement(node as ForStatement);
1483                    case SyntaxKind.ForInStatement:
1484                        return emitForInStatement(node as ForInStatement);
1485                    case SyntaxKind.ForOfStatement:
1486                        return emitForOfStatement(node as ForOfStatement);
1487                    case SyntaxKind.ContinueStatement:
1488                        return emitContinueStatement(node as ContinueStatement);
1489                    case SyntaxKind.BreakStatement:
1490                        return emitBreakStatement(node as BreakStatement);
1491                    case SyntaxKind.ReturnStatement:
1492                        return emitReturnStatement(node as ReturnStatement);
1493                    case SyntaxKind.WithStatement:
1494                        return emitWithStatement(node as WithStatement);
1495                    case SyntaxKind.SwitchStatement:
1496                        return emitSwitchStatement(node as SwitchStatement);
1497                    case SyntaxKind.LabeledStatement:
1498                        return emitLabeledStatement(node as LabeledStatement);
1499                    case SyntaxKind.ThrowStatement:
1500                        return emitThrowStatement(node as ThrowStatement);
1501                    case SyntaxKind.TryStatement:
1502                        return emitTryStatement(node as TryStatement);
1503                    case SyntaxKind.DebuggerStatement:
1504                        return emitDebuggerStatement(node as DebuggerStatement);
1505
1506                    // Declarations
1507                    case SyntaxKind.VariableDeclaration:
1508                        return emitVariableDeclaration(node as VariableDeclaration);
1509                    case SyntaxKind.VariableDeclarationList:
1510                        return emitVariableDeclarationList(node as VariableDeclarationList);
1511                    case SyntaxKind.FunctionDeclaration:
1512                        return emitFunctionDeclaration(node as FunctionDeclaration);
1513                    case SyntaxKind.ClassDeclaration:
1514                        return emitClassOrStructDeclaration(node as ClassDeclaration);
1515                    case SyntaxKind.StructDeclaration:
1516                        return emitClassOrStructDeclaration(<StructDeclaration>node);
1517                    case SyntaxKind.InterfaceDeclaration:
1518                        return emitInterfaceDeclaration(node as InterfaceDeclaration);
1519                    case SyntaxKind.TypeAliasDeclaration:
1520                        return emitTypeAliasDeclaration(node as TypeAliasDeclaration);
1521                    case SyntaxKind.EnumDeclaration:
1522                        return emitEnumDeclaration(node as EnumDeclaration);
1523                    case SyntaxKind.ModuleDeclaration:
1524                        return emitModuleDeclaration(node as ModuleDeclaration);
1525                    case SyntaxKind.ModuleBlock:
1526                        return emitModuleBlock(node as ModuleBlock);
1527                    case SyntaxKind.CaseBlock:
1528                        return emitCaseBlock(node as CaseBlock);
1529                    case SyntaxKind.NamespaceExportDeclaration:
1530                        return emitNamespaceExportDeclaration(node as NamespaceExportDeclaration);
1531                    case SyntaxKind.ImportEqualsDeclaration:
1532                        return emitImportEqualsDeclaration(node as ImportEqualsDeclaration);
1533                    case SyntaxKind.ImportDeclaration:
1534                        return emitImportDeclaration(node as ImportDeclaration);
1535                    case SyntaxKind.ImportClause:
1536                        return emitImportClause(node as ImportClause);
1537                    case SyntaxKind.NamespaceImport:
1538                        return emitNamespaceImport(node as NamespaceImport);
1539                    case SyntaxKind.NamespaceExport:
1540                        return emitNamespaceExport(node as NamespaceExport);
1541                    case SyntaxKind.NamedImports:
1542                        return emitNamedImports(node as NamedImports);
1543                    case SyntaxKind.ImportSpecifier:
1544                        return emitImportSpecifier(node as ImportSpecifier);
1545                    case SyntaxKind.ExportAssignment:
1546                        return emitExportAssignment(node as ExportAssignment);
1547                    case SyntaxKind.ExportDeclaration:
1548                        return emitExportDeclaration(node as ExportDeclaration);
1549                    case SyntaxKind.NamedExports:
1550                        return emitNamedExports(node as NamedExports);
1551                    case SyntaxKind.ExportSpecifier:
1552                        return emitExportSpecifier(node as ExportSpecifier);
1553                    case SyntaxKind.AssertClause:
1554                        return emitAssertClause(node as AssertClause);
1555                    case SyntaxKind.AssertEntry:
1556                        return emitAssertEntry(node as AssertEntry);
1557                    case SyntaxKind.MissingDeclaration:
1558                        return;
1559
1560                    // Module references
1561                    case SyntaxKind.ExternalModuleReference:
1562                        return emitExternalModuleReference(node as ExternalModuleReference);
1563
1564                    // JSX (non-expression)
1565                    case SyntaxKind.JsxText:
1566                        return emitJsxText(node as JsxText);
1567                    case SyntaxKind.JsxOpeningElement:
1568                    case SyntaxKind.JsxOpeningFragment:
1569                        return emitJsxOpeningElementOrFragment(node as JsxOpeningElement);
1570                    case SyntaxKind.JsxClosingElement:
1571                    case SyntaxKind.JsxClosingFragment:
1572                        return emitJsxClosingElementOrFragment(node as JsxClosingElement);
1573                    case SyntaxKind.JsxAttribute:
1574                        return emitJsxAttribute(node as JsxAttribute);
1575                    case SyntaxKind.JsxAttributes:
1576                        return emitJsxAttributes(node as JsxAttributes);
1577                    case SyntaxKind.JsxSpreadAttribute:
1578                        return emitJsxSpreadAttribute(node as JsxSpreadAttribute);
1579                    case SyntaxKind.JsxExpression:
1580                        return emitJsxExpression(node as JsxExpression);
1581
1582                    // Clauses
1583                    case SyntaxKind.CaseClause:
1584                        return emitCaseClause(node as CaseClause);
1585                    case SyntaxKind.DefaultClause:
1586                        return emitDefaultClause(node as DefaultClause);
1587                    case SyntaxKind.HeritageClause:
1588                        return emitHeritageClause(node as HeritageClause);
1589                    case SyntaxKind.CatchClause:
1590                        return emitCatchClause(node as CatchClause);
1591
1592                    // Property assignments
1593                    case SyntaxKind.PropertyAssignment:
1594                        return emitPropertyAssignment(node as PropertyAssignment);
1595                    case SyntaxKind.ShorthandPropertyAssignment:
1596                        return emitShorthandPropertyAssignment(node as ShorthandPropertyAssignment);
1597                    case SyntaxKind.SpreadAssignment:
1598                        return emitSpreadAssignment(node as SpreadAssignment);
1599
1600                    // Enum
1601                    case SyntaxKind.EnumMember:
1602                        return emitEnumMember(node as EnumMember);
1603
1604                    // Unparsed
1605                    case SyntaxKind.UnparsedPrologue:
1606                        return writeUnparsedNode(node as UnparsedNode);
1607                    case SyntaxKind.UnparsedSource:
1608                    case SyntaxKind.UnparsedPrepend:
1609                        return emitUnparsedSourceOrPrepend(node as UnparsedSource);
1610                    case SyntaxKind.UnparsedText:
1611                    case SyntaxKind.UnparsedInternalText:
1612                        return emitUnparsedTextLike(node as UnparsedTextLike);
1613                    case SyntaxKind.UnparsedSyntheticReference:
1614                        return emitUnparsedSyntheticReference(node as UnparsedSyntheticReference);
1615
1616                    // Top-level nodes
1617                    case SyntaxKind.SourceFile:
1618                        return emitSourceFile(node as SourceFile);
1619                    case SyntaxKind.Bundle:
1620                        return Debug.fail("Bundles should be printed using printBundle");
1621                    // SyntaxKind.UnparsedSource (handled above)
1622                    case SyntaxKind.InputFiles:
1623                        return Debug.fail("InputFiles should not be printed");
1624
1625                    // JSDoc nodes (only used in codefixes currently)
1626                    case SyntaxKind.JSDocTypeExpression:
1627                        return emitJSDocTypeExpression(node as JSDocTypeExpression);
1628                    case SyntaxKind.JSDocNameReference:
1629                        return emitJSDocNameReference(node as JSDocNameReference);
1630                    case SyntaxKind.JSDocAllType:
1631                        return writePunctuation("*");
1632                    case SyntaxKind.JSDocUnknownType:
1633                        return writePunctuation("?");
1634                    case SyntaxKind.JSDocNullableType:
1635                        return emitJSDocNullableType(node as JSDocNullableType);
1636                    case SyntaxKind.JSDocNonNullableType:
1637                        return emitJSDocNonNullableType(node as JSDocNonNullableType);
1638                    case SyntaxKind.JSDocOptionalType:
1639                        return emitJSDocOptionalType(node as JSDocOptionalType);
1640                    case SyntaxKind.JSDocFunctionType:
1641                        return emitJSDocFunctionType(node as JSDocFunctionType);
1642                    case SyntaxKind.RestType:
1643                    case SyntaxKind.JSDocVariadicType:
1644                        return emitRestOrJSDocVariadicType(node as RestTypeNode | JSDocVariadicType);
1645                    case SyntaxKind.JSDocNamepathType:
1646                        return;
1647                    case SyntaxKind.JSDoc:
1648                        return emitJSDoc(node as JSDoc);
1649                    case SyntaxKind.JSDocTypeLiteral:
1650                        return emitJSDocTypeLiteral(node as JSDocTypeLiteral);
1651                    case SyntaxKind.JSDocSignature:
1652                        return emitJSDocSignature(node as JSDocSignature);
1653                    case SyntaxKind.JSDocTag:
1654                    case SyntaxKind.JSDocClassTag:
1655                    case SyntaxKind.JSDocOverrideTag:
1656                        return emitJSDocSimpleTag(node as JSDocTag);
1657                    case SyntaxKind.JSDocAugmentsTag:
1658                    case SyntaxKind.JSDocImplementsTag:
1659                        return emitJSDocHeritageTag(node as JSDocImplementsTag | JSDocAugmentsTag);
1660                    case SyntaxKind.JSDocAuthorTag:
1661                    case SyntaxKind.JSDocDeprecatedTag:
1662                        return;
1663                    // SyntaxKind.JSDocClassTag (see JSDocTag, above)
1664                    case SyntaxKind.JSDocPublicTag:
1665                    case SyntaxKind.JSDocPrivateTag:
1666                    case SyntaxKind.JSDocProtectedTag:
1667                    case SyntaxKind.JSDocReadonlyTag:
1668                        return;
1669                    case SyntaxKind.JSDocCallbackTag:
1670                        return emitJSDocCallbackTag(node as JSDocCallbackTag);
1671                    // SyntaxKind.JSDocEnumTag (see below)
1672                    case SyntaxKind.JSDocParameterTag:
1673                    case SyntaxKind.JSDocPropertyTag:
1674                        return emitJSDocPropertyLikeTag(node as JSDocPropertyLikeTag);
1675                    case SyntaxKind.JSDocEnumTag:
1676                    case SyntaxKind.JSDocReturnTag:
1677                    case SyntaxKind.JSDocThisTag:
1678                    case SyntaxKind.JSDocTypeTag:
1679                        return emitJSDocSimpleTypedTag(node as JSDocTypeTag);
1680                    case SyntaxKind.JSDocTemplateTag:
1681                        return emitJSDocTemplateTag(node as JSDocTemplateTag);
1682                    case SyntaxKind.JSDocTypedefTag:
1683                        return emitJSDocTypedefTag(node as JSDocTypedefTag);
1684                    case SyntaxKind.JSDocSeeTag:
1685                        return emitJSDocSeeTag(node as JSDocSeeTag);
1686                    // SyntaxKind.JSDocPropertyTag (see JSDocParameterTag, above)
1687
1688                    // Transformation nodes
1689                    case SyntaxKind.NotEmittedStatement:
1690                    case SyntaxKind.EndOfDeclarationMarker:
1691                    case SyntaxKind.MergeDeclarationMarker:
1692                        return;
1693                }
1694                if (isExpression(node)) {
1695                    hint = EmitHint.Expression;
1696                    if (substituteNode !== noEmitSubstitution) {
1697                        const substitute = substituteNode(hint, node) || node;
1698                        if (substitute !== node) {
1699                            node = substitute;
1700                            if (currentParenthesizerRule) {
1701                                node = currentParenthesizerRule(node);
1702                            }
1703                        }
1704                    }
1705                }
1706            }
1707            if (hint === EmitHint.Expression) {
1708                switch (node.kind) {
1709                    // Literals
1710                    case SyntaxKind.NumericLiteral:
1711                    case SyntaxKind.BigIntLiteral:
1712                        return emitNumericOrBigIntLiteral(node as NumericLiteral | BigIntLiteral);
1713
1714                    case SyntaxKind.StringLiteral:
1715                    case SyntaxKind.RegularExpressionLiteral:
1716                    case SyntaxKind.NoSubstitutionTemplateLiteral:
1717                        return emitLiteral(node as LiteralExpression, /*jsxAttributeEscape*/ false);
1718
1719                    // Identifiers
1720                    case SyntaxKind.Identifier:
1721                        return emitIdentifier(node as Identifier);
1722                    case SyntaxKind.PrivateIdentifier:
1723                        return emitPrivateIdentifier(node as PrivateIdentifier);
1724
1725                    // Expressions
1726                    case SyntaxKind.ArrayLiteralExpression:
1727                        return emitArrayLiteralExpression(node as ArrayLiteralExpression);
1728                    case SyntaxKind.ObjectLiteralExpression:
1729                        return emitObjectLiteralExpression(node as ObjectLiteralExpression);
1730                    case SyntaxKind.PropertyAccessExpression:
1731                        return emitPropertyAccessExpression(node as PropertyAccessExpression);
1732                    case SyntaxKind.ElementAccessExpression:
1733                        return emitElementAccessExpression(node as ElementAccessExpression);
1734                    case SyntaxKind.CallExpression:
1735                        return emitCallExpression(node as CallExpression);
1736                    case SyntaxKind.NewExpression:
1737                        return emitNewExpression(node as NewExpression);
1738                    case SyntaxKind.TaggedTemplateExpression:
1739                        return emitTaggedTemplateExpression(node as TaggedTemplateExpression);
1740                    case SyntaxKind.TypeAssertionExpression:
1741                        return emitTypeAssertionExpression(node as TypeAssertion);
1742                    case SyntaxKind.ParenthesizedExpression:
1743                        return emitParenthesizedExpression(node as ParenthesizedExpression);
1744                    case SyntaxKind.FunctionExpression:
1745                        return emitFunctionExpression(node as FunctionExpression);
1746                    case SyntaxKind.ArrowFunction:
1747                        return emitArrowFunction(node as ArrowFunction);
1748                    case SyntaxKind.DeleteExpression:
1749                        return emitDeleteExpression(node as DeleteExpression);
1750                    case SyntaxKind.TypeOfExpression:
1751                        return emitTypeOfExpression(node as TypeOfExpression);
1752                    case SyntaxKind.VoidExpression:
1753                        return emitVoidExpression(node as VoidExpression);
1754                    case SyntaxKind.AwaitExpression:
1755                        return emitAwaitExpression(node as AwaitExpression);
1756                    case SyntaxKind.PrefixUnaryExpression:
1757                        return emitPrefixUnaryExpression(node as PrefixUnaryExpression);
1758                    case SyntaxKind.PostfixUnaryExpression:
1759                        return emitPostfixUnaryExpression(node as PostfixUnaryExpression);
1760                    case SyntaxKind.BinaryExpression:
1761                        return emitBinaryExpression(node as BinaryExpression);
1762                    case SyntaxKind.ConditionalExpression:
1763                        return emitConditionalExpression(node as ConditionalExpression);
1764                    case SyntaxKind.TemplateExpression:
1765                        return emitTemplateExpression(node as TemplateExpression);
1766                    case SyntaxKind.YieldExpression:
1767                        return emitYieldExpression(node as YieldExpression);
1768                    case SyntaxKind.SpreadElement:
1769                        return emitSpreadElement(node as SpreadElement);
1770                    case SyntaxKind.ClassExpression:
1771                        return emitClassExpression(node as ClassExpression);
1772                    case SyntaxKind.OmittedExpression:
1773                        return;
1774                    case SyntaxKind.AsExpression:
1775                        return emitAsExpression(node as AsExpression);
1776                    case SyntaxKind.NonNullExpression:
1777                        return emitNonNullExpression(node as NonNullExpression);
1778                    case SyntaxKind.ExpressionWithTypeArguments:
1779                        return emitExpressionWithTypeArguments(node as ExpressionWithTypeArguments);
1780                    case SyntaxKind.SatisfiesExpression:
1781                        return emitSatisfiesExpression(node as SatisfiesExpression);
1782                    case SyntaxKind.MetaProperty:
1783                        return emitMetaProperty(node as MetaProperty);
1784                    case SyntaxKind.SyntheticExpression:
1785                        return Debug.fail("SyntheticExpression should never be printed.");
1786
1787                    // JSX
1788                    case SyntaxKind.JsxElement:
1789                        return emitJsxElement(node as JsxElement);
1790                    case SyntaxKind.JsxSelfClosingElement:
1791                        return emitJsxSelfClosingElement(node as JsxSelfClosingElement);
1792                    case SyntaxKind.JsxFragment:
1793                        return emitJsxFragment(node as JsxFragment);
1794
1795                    // Synthesized list
1796                    case SyntaxKind.SyntaxList:
1797                        return Debug.fail("SyntaxList should not be printed");
1798
1799                    // Transformation nodes
1800                    case SyntaxKind.NotEmittedStatement:
1801                        return;
1802                    case SyntaxKind.PartiallyEmittedExpression:
1803                        return emitPartiallyEmittedExpression(node as PartiallyEmittedExpression);
1804                    case SyntaxKind.CommaListExpression:
1805                        return emitCommaList(node as CommaListExpression);
1806                    case SyntaxKind.MergeDeclarationMarker:
1807                    case SyntaxKind.EndOfDeclarationMarker:
1808                        return;
1809                    case SyntaxKind.SyntheticReferenceExpression:
1810                        return Debug.fail("SyntheticReferenceExpression should not be printed");
1811                }
1812            }
1813            if (isKeyword(node.kind)) return writeTokenNode(node, writeKeyword);
1814            if (isTokenKind(node.kind)) return writeTokenNode(node, writePunctuation);
1815            // skip emit root component expression
1816            if (findAncestor(node, (elelment: Node) => {
1817                return isEtsComponentExpression(elelment)
1818            })) {
1819                return;
1820            }
1821            Debug.fail(`Unhandled SyntaxKind: ${Debug.formatSyntaxKind(node.kind)}.`);
1822        }
1823
1824        function emitMappedTypeParameter(node: TypeParameterDeclaration): void {
1825            emit(node.name);
1826            writeSpace();
1827            writeKeyword("in");
1828            writeSpace();
1829            emit(node.constraint);
1830        }
1831
1832        function pipelineEmitWithSubstitution(hint: EmitHint, node: Node) {
1833            const pipelinePhase = getNextPipelinePhase(PipelinePhase.Substitution, hint, node);
1834            Debug.assertIsDefined(lastSubstitution);
1835            node = lastSubstitution;
1836            lastSubstitution = undefined;
1837            pipelinePhase(hint, node);
1838        }
1839
1840        function getHelpersFromBundledSourceFiles(bundle: Bundle): string[] | undefined {
1841            let result: string[] | undefined;
1842            if (moduleKind === ModuleKind.None || printerOptions.noEmitHelpers) {
1843                return undefined;
1844            }
1845            const bundledHelpers = new Map<string, boolean>();
1846            for (const sourceFile of bundle.sourceFiles) {
1847                const shouldSkip = getExternalHelpersModuleName(sourceFile) !== undefined;
1848                const helpers = getSortedEmitHelpers(sourceFile);
1849                if (!helpers) continue;
1850                for (const helper of helpers) {
1851                    if (!helper.scoped && !shouldSkip && !bundledHelpers.get(helper.name)) {
1852                        bundledHelpers.set(helper.name, true);
1853                        (result || (result = [])).push(helper.name);
1854                    }
1855                }
1856            }
1857
1858            return result;
1859        }
1860
1861        function emitHelpers(node: Node) {
1862            let helpersEmitted = false;
1863            const bundle = node.kind === SyntaxKind.Bundle ? node as Bundle : undefined;
1864            if (bundle && moduleKind === ModuleKind.None) {
1865                return;
1866            }
1867            const numPrepends = bundle ? bundle.prepends.length : 0;
1868            const numNodes = bundle ? bundle.sourceFiles.length + numPrepends : 1;
1869            for (let i = 0; i < numNodes; i++) {
1870                const currentNode = bundle ? i < numPrepends ? bundle.prepends[i] : bundle.sourceFiles[i - numPrepends] : node;
1871                const sourceFile = isSourceFile(currentNode) ? currentNode : isUnparsedSource(currentNode) ? undefined : currentSourceFile;
1872                const shouldSkip = printerOptions.noEmitHelpers || (!!sourceFile && hasRecordedExternalHelpers(sourceFile));
1873                const shouldBundle = (isSourceFile(currentNode) || isUnparsedSource(currentNode)) && !isOwnFileEmit;
1874                const helpers = isUnparsedSource(currentNode) ? currentNode.helpers : getSortedEmitHelpers(currentNode);
1875                if (helpers) {
1876                    for (const helper of helpers) {
1877                        if (!helper.scoped) {
1878                            // Skip the helper if it can be skipped and the noEmitHelpers compiler
1879                            // option is set, or if it can be imported and the importHelpers compiler
1880                            // option is set.
1881                            if (shouldSkip) continue;
1882
1883                            // Skip the helper if it can be bundled but hasn't already been emitted and we
1884                            // are emitting a bundled module.
1885                            if (shouldBundle) {
1886                                if (bundledHelpers.get(helper.name)) {
1887                                    continue;
1888                                }
1889
1890                                bundledHelpers.set(helper.name, true);
1891                            }
1892                        }
1893                        else if (bundle) {
1894                            // Skip the helper if it is scoped and we are emitting bundled helpers
1895                            continue;
1896                        }
1897                        const pos = getTextPosWithWriteLine();
1898                        if (typeof helper.text === "string") {
1899                            writeLines(helper.text);
1900                        }
1901                        else {
1902                            writeLines(helper.text(makeFileLevelOptimisticUniqueName));
1903                        }
1904                        if (bundleFileInfo) bundleFileInfo.sections.push({ pos, end: writer.getTextPos(), kind: BundleFileSectionKind.EmitHelpers, data: helper.name });
1905                        helpersEmitted = true;
1906                    }
1907                }
1908            }
1909
1910            return helpersEmitted;
1911        }
1912
1913        function getSortedEmitHelpers(node: Node) {
1914            const helpers = getEmitHelpers(node);
1915            return helpers && stableSort(helpers, compareEmitHelpers);
1916        }
1917
1918        //
1919        // Literals/Pseudo-literals
1920        //
1921
1922        // SyntaxKind.NumericLiteral
1923        // SyntaxKind.BigIntLiteral
1924        function emitNumericOrBigIntLiteral(node: NumericLiteral | BigIntLiteral) {
1925            emitLiteral(node, /*jsxAttributeEscape*/ false);
1926        }
1927
1928        // SyntaxKind.StringLiteral
1929        // SyntaxKind.RegularExpressionLiteral
1930        // SyntaxKind.NoSubstitutionTemplateLiteral
1931        // SyntaxKind.TemplateHead
1932        // SyntaxKind.TemplateMiddle
1933        // SyntaxKind.TemplateTail
1934        function emitLiteral(node: LiteralLikeNode, jsxAttributeEscape: boolean) {
1935            const text = getLiteralTextOfNode(node, printerOptions.neverAsciiEscape, jsxAttributeEscape);
1936            if ((printerOptions.sourceMap || printerOptions.inlineSourceMap)
1937                && (node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind))) {
1938                writeLiteral(text);
1939            }
1940            else {
1941                // Quick info expects all literals to be called with writeStringLiteral, as there's no specific type for numberLiterals
1942                writeStringLiteral(text);
1943            }
1944        }
1945
1946        // SyntaxKind.UnparsedSource
1947        // SyntaxKind.UnparsedPrepend
1948        function emitUnparsedSourceOrPrepend(unparsed: UnparsedSource | UnparsedPrepend) {
1949            for (const text of unparsed.texts) {
1950                writeLine();
1951                emit(text);
1952            }
1953        }
1954
1955        // SyntaxKind.UnparsedPrologue
1956        // SyntaxKind.UnparsedText
1957        // SyntaxKind.UnparsedInternal
1958        // SyntaxKind.UnparsedSyntheticReference
1959        function writeUnparsedNode(unparsed: UnparsedNode) {
1960            writer.rawWrite(unparsed.parent.text.substring(unparsed.pos, unparsed.end));
1961        }
1962
1963        // SyntaxKind.UnparsedText
1964        // SyntaxKind.UnparsedInternal
1965        function emitUnparsedTextLike(unparsed: UnparsedTextLike) {
1966            const pos = getTextPosWithWriteLine();
1967            writeUnparsedNode(unparsed);
1968            if (bundleFileInfo) {
1969                updateOrPushBundleFileTextLike(
1970                    pos,
1971                    writer.getTextPos(),
1972                    unparsed.kind === SyntaxKind.UnparsedText ?
1973                        BundleFileSectionKind.Text :
1974                        BundleFileSectionKind.Internal
1975                );
1976            }
1977        }
1978
1979        // SyntaxKind.UnparsedSyntheticReference
1980        function emitUnparsedSyntheticReference(unparsed: UnparsedSyntheticReference) {
1981            const pos = getTextPosWithWriteLine();
1982            writeUnparsedNode(unparsed);
1983            if (bundleFileInfo) {
1984                const section = clone(unparsed.section);
1985                section.pos = pos;
1986                section.end = writer.getTextPos();
1987                bundleFileInfo.sections.push(section);
1988            }
1989        }
1990
1991        //
1992        // Snippet Elements
1993        //
1994
1995        function emitSnippetNode(hint: EmitHint, node: Node, snippet: SnippetElement) {
1996            switch (snippet.kind) {
1997                case SnippetKind.Placeholder:
1998                    emitPlaceholder(hint, node, snippet);
1999                    break;
2000                case SnippetKind.TabStop:
2001                    emitTabStop(hint, node, snippet);
2002                    break;
2003            }
2004        }
2005
2006        function emitPlaceholder(hint: EmitHint, node: Node, snippet: Placeholder) {
2007            nonEscapingWrite(`\$\{${snippet.order}:`); // `${2:`
2008            pipelineEmitWithHintWorker(hint, node, /*allowSnippets*/ false); // `...`
2009            nonEscapingWrite(`\}`); // `}`
2010            // `${2:...}`
2011        }
2012
2013        function emitTabStop(hint: EmitHint, node: Node, snippet: TabStop) {
2014            // A tab stop should only be attached to an empty node, i.e. a node that doesn't emit any text.
2015            Debug.assert(node.kind === SyntaxKind.EmptyStatement,
2016                `A tab stop cannot be attached to a node of kind ${Debug.formatSyntaxKind(node.kind)}.`);
2017            Debug.assert(hint !== EmitHint.EmbeddedStatement,
2018                `A tab stop cannot be attached to an embedded statement.`);
2019            nonEscapingWrite(`\$${snippet.order}`);
2020        }
2021
2022        //
2023        // Identifiers
2024        //
2025
2026        function emitIdentifier(node: Identifier) {
2027            const writeText = node.symbol ? writeSymbol : write;
2028            writeText(getTextOfNode(node, /*includeTrivia*/ false), node.symbol);
2029            emitList(node, node.typeArguments, ListFormat.TypeParameters); // Call emitList directly since it could be an array of TypeParameterDeclarations _or_ type arguments
2030        }
2031
2032        //
2033        // Names
2034        //
2035
2036        function emitPrivateIdentifier(node: PrivateIdentifier) {
2037            const writeText = node.symbol ? writeSymbol : write;
2038            writeText(getTextOfNode(node, /*includeTrivia*/ false), node.symbol);
2039        }
2040
2041
2042        function emitQualifiedName(node: QualifiedName) {
2043            emitEntityName(node.left);
2044            writePunctuation(".");
2045            emit(node.right);
2046        }
2047
2048        function emitEntityName(node: EntityName) {
2049            if (node.kind === SyntaxKind.Identifier) {
2050                emitExpression(node);
2051            }
2052            else {
2053                emit(node);
2054            }
2055        }
2056
2057        function emitComputedPropertyName(node: ComputedPropertyName) {
2058            writePunctuation("[");
2059            emitExpression(node.expression, parenthesizer.parenthesizeExpressionOfComputedPropertyName);
2060            writePunctuation("]");
2061        }
2062
2063        //
2064        // Signature elements
2065        //
2066
2067        function emitTypeParameter(node: TypeParameterDeclaration) {
2068            emitModifiers(node, node.modifiers);
2069            emit(node.name);
2070            if (node.constraint) {
2071                writeSpace();
2072                writeKeyword("extends");
2073                writeSpace();
2074                emit(node.constraint);
2075            }
2076            if (node.default) {
2077                writeSpace();
2078                writeOperator("=");
2079                writeSpace();
2080                emit(node.default);
2081            }
2082        }
2083
2084        function emitParameter(node: ParameterDeclaration) {
2085            emitDecoratorsAndModifiers(node, node.modifiers);
2086            emit(node.dotDotDotToken);
2087            emitNodeWithWriter(node.name, writeParameter);
2088            emit(node.questionToken);
2089            if (node.parent && node.parent.kind === SyntaxKind.JSDocFunctionType && !node.name) {
2090                emit(node.type);
2091            }
2092            else {
2093                emitTypeAnnotation(node.type);
2094            }
2095            // The comment position has to fallback to any present node within the parameterdeclaration because as it turns out, the parser can make parameter declarations with _just_ an initializer.
2096            emitInitializer(node.initializer, node.type ? node.type.end : node.questionToken ? node.questionToken.end : node.name ? node.name.end : node.modifiers ? node.modifiers.end : node.pos, node, parenthesizer.parenthesizeExpressionForDisallowedComma);
2097        }
2098
2099        function emitDecorator(decorator: Decorator) {
2100            writePunctuation("@");
2101            emitExpression(decorator.expression, parenthesizer.parenthesizeLeftSideOfAccess);
2102        }
2103
2104        //
2105        // Type members
2106        //
2107
2108        function emitPropertySignature(node: PropertySignature) {
2109            emitModifiers(node, node.modifiers);
2110            emitNodeWithWriter(node.name, writeProperty);
2111            emit(node.questionToken);
2112            emitTypeAnnotation(node.type);
2113            writeTrailingSemicolon();
2114        }
2115
2116        function emitPropertyDeclaration(node: PropertyDeclaration) {
2117            emitDecoratorsAndModifiers(node, node.modifiers);
2118            emit(node.name);
2119            emit(node.questionToken);
2120            emit(node.exclamationToken);
2121            emitTypeAnnotation(node.type);
2122            emitInitializer(node.initializer, node.type ? node.type.end : node.questionToken ? node.questionToken.end : node.name.end, node);
2123            writeTrailingSemicolon();
2124        }
2125
2126        function emitMethodSignature(node: MethodSignature) {
2127            pushNameGenerationScope(node);
2128            emitModifiers(node, node.modifiers);
2129            emit(node.name);
2130            emit(node.questionToken);
2131            emitTypeParameters(node, node.typeParameters);
2132            emitParameters(node, node.parameters);
2133            emitTypeAnnotation(node.type);
2134            writeTrailingSemicolon();
2135            popNameGenerationScope(node);
2136        }
2137
2138        function emitMethodDeclaration(node: MethodDeclaration) {
2139            emitDecoratorsAndModifiers(node, node.modifiers);
2140            emit(node.asteriskToken);
2141            emit(node.name);
2142            emit(node.questionToken);
2143            emitSignatureAndBody(node, emitSignatureHead);
2144        }
2145
2146        function emitClassStaticBlockDeclaration(node: ClassStaticBlockDeclaration) {
2147            writeKeyword("static");
2148            emitBlockFunctionBody(node.body);
2149        }
2150
2151        function emitConstructor(node: ConstructorDeclaration) {
2152            emitModifiers(node, node.modifiers);
2153            writeKeyword("constructor");
2154            emitSignatureAndBody(node, emitSignatureHead);
2155        }
2156
2157        function emitAccessorDeclaration(node: AccessorDeclaration) {
2158            emitDecoratorsAndModifiers(node, node.modifiers);
2159            writeKeyword(node.kind === SyntaxKind.GetAccessor ? "get" : "set");
2160            writeSpace();
2161            emit(node.name);
2162            emitSignatureAndBody(node, emitSignatureHead);
2163        }
2164
2165        function emitCallSignature(node: CallSignatureDeclaration) {
2166            pushNameGenerationScope(node);
2167            emitTypeParameters(node, node.typeParameters);
2168            emitParameters(node, node.parameters);
2169            emitTypeAnnotation(node.type);
2170            writeTrailingSemicolon();
2171            popNameGenerationScope(node);
2172        }
2173
2174        function emitConstructSignature(node: ConstructSignatureDeclaration) {
2175            pushNameGenerationScope(node);
2176            writeKeyword("new");
2177            writeSpace();
2178            emitTypeParameters(node, node.typeParameters);
2179            emitParameters(node, node.parameters);
2180            emitTypeAnnotation(node.type);
2181            writeTrailingSemicolon();
2182            popNameGenerationScope(node);
2183        }
2184
2185        function emitIndexSignature(node: IndexSignatureDeclaration) {
2186            emitModifiers(node, node.modifiers);
2187            emitParametersForIndexSignature(node, node.parameters);
2188            emitTypeAnnotation(node.type);
2189            writeTrailingSemicolon();
2190        }
2191
2192        function emitTemplateTypeSpan(node: TemplateLiteralTypeSpan) {
2193            emit(node.type);
2194            emit(node.literal);
2195        }
2196
2197        function emitSemicolonClassElement() {
2198            writeTrailingSemicolon();
2199        }
2200
2201        //
2202        // Types
2203        //
2204
2205        function emitTypePredicate(node: TypePredicateNode) {
2206            if (node.assertsModifier) {
2207                emit(node.assertsModifier);
2208                writeSpace();
2209            }
2210            emit(node.parameterName);
2211            if (node.type) {
2212                writeSpace();
2213                writeKeyword("is");
2214                writeSpace();
2215                emit(node.type);
2216            }
2217        }
2218
2219        function emitTypeReference(node: TypeReferenceNode) {
2220            emit(node.typeName);
2221            emitTypeArguments(node, node.typeArguments);
2222        }
2223
2224        function emitFunctionType(node: FunctionTypeNode) {
2225            pushNameGenerationScope(node);
2226            emitTypeParameters(node, node.typeParameters);
2227            emitParametersForArrow(node, node.parameters);
2228            writeSpace();
2229            writePunctuation("=>");
2230            writeSpace();
2231            emit(node.type);
2232            popNameGenerationScope(node);
2233        }
2234
2235        function emitJSDocFunctionType(node: JSDocFunctionType) {
2236            writeKeyword("function");
2237            emitParameters(node, node.parameters);
2238            writePunctuation(":");
2239            emit(node.type);
2240        }
2241
2242
2243        function emitJSDocNullableType(node: JSDocNullableType) {
2244            writePunctuation("?");
2245            emit(node.type);
2246        }
2247
2248        function emitJSDocNonNullableType(node: JSDocNonNullableType) {
2249            writePunctuation("!");
2250            emit(node.type);
2251        }
2252
2253        function emitJSDocOptionalType(node: JSDocOptionalType) {
2254            emit(node.type);
2255            writePunctuation("=");
2256        }
2257
2258        function emitConstructorType(node: ConstructorTypeNode) {
2259            pushNameGenerationScope(node);
2260            emitModifiers(node, node.modifiers);
2261            writeKeyword("new");
2262            writeSpace();
2263            emitTypeParameters(node, node.typeParameters);
2264            emitParameters(node, node.parameters);
2265            writeSpace();
2266            writePunctuation("=>");
2267            writeSpace();
2268            emit(node.type);
2269            popNameGenerationScope(node);
2270        }
2271
2272        function emitTypeQuery(node: TypeQueryNode) {
2273            writeKeyword("typeof");
2274            writeSpace();
2275            emit(node.exprName);
2276            emitTypeArguments(node, node.typeArguments);
2277        }
2278
2279        function emitTypeLiteral(node: TypeLiteralNode) {
2280            writePunctuation("{");
2281            const flags = getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineTypeLiteralMembers : ListFormat.MultiLineTypeLiteralMembers;
2282            emitList(node, node.members, flags | ListFormat.NoSpaceIfEmpty);
2283            writePunctuation("}");
2284        }
2285
2286        function emitArrayType(node: ArrayTypeNode) {
2287            emit(node.elementType, parenthesizer.parenthesizeNonArrayTypeOfPostfixType);
2288            writePunctuation("[");
2289            writePunctuation("]");
2290        }
2291
2292        function emitRestOrJSDocVariadicType(node: RestTypeNode | JSDocVariadicType) {
2293            writePunctuation("...");
2294            emit(node.type);
2295        }
2296
2297        function emitTupleType(node: TupleTypeNode) {
2298            emitTokenWithComment(SyntaxKind.OpenBracketToken, node.pos, writePunctuation, node);
2299            const flags = getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineTupleTypeElements : ListFormat.MultiLineTupleTypeElements;
2300            emitList(node, node.elements, flags | ListFormat.NoSpaceIfEmpty, parenthesizer.parenthesizeElementTypeOfTupleType);
2301            emitTokenWithComment(SyntaxKind.CloseBracketToken, node.elements.end, writePunctuation, node);
2302        }
2303
2304        function emitNamedTupleMember(node: NamedTupleMember) {
2305            emit(node.dotDotDotToken);
2306            emit(node.name);
2307            emit(node.questionToken);
2308            emitTokenWithComment(SyntaxKind.ColonToken, node.name.end, writePunctuation, node);
2309            writeSpace();
2310            emit(node.type);
2311        }
2312
2313        function emitOptionalType(node: OptionalTypeNode) {
2314            emit(node.type, parenthesizer.parenthesizeTypeOfOptionalType);
2315            writePunctuation("?");
2316        }
2317
2318        function emitUnionType(node: UnionTypeNode) {
2319            emitList(node, node.types, ListFormat.UnionTypeConstituents, parenthesizer.parenthesizeConstituentTypeOfUnionType);
2320        }
2321
2322        function emitIntersectionType(node: IntersectionTypeNode) {
2323            emitList(node, node.types, ListFormat.IntersectionTypeConstituents, parenthesizer.parenthesizeConstituentTypeOfIntersectionType);
2324        }
2325
2326        function emitConditionalType(node: ConditionalTypeNode) {
2327            emit(node.checkType, parenthesizer.parenthesizeCheckTypeOfConditionalType);
2328            writeSpace();
2329            writeKeyword("extends");
2330            writeSpace();
2331            emit(node.extendsType, parenthesizer.parenthesizeExtendsTypeOfConditionalType);
2332            writeSpace();
2333            writePunctuation("?");
2334            writeSpace();
2335            emit(node.trueType);
2336            writeSpace();
2337            writePunctuation(":");
2338            writeSpace();
2339            emit(node.falseType);
2340        }
2341
2342        function emitInferType(node: InferTypeNode) {
2343            writeKeyword("infer");
2344            writeSpace();
2345            emit(node.typeParameter);
2346        }
2347
2348        function emitParenthesizedType(node: ParenthesizedTypeNode) {
2349            writePunctuation("(");
2350            emit(node.type);
2351            writePunctuation(")");
2352        }
2353
2354        function emitThisType() {
2355            writeKeyword("this");
2356        }
2357
2358        function emitTypeOperator(node: TypeOperatorNode) {
2359            writeTokenText(node.operator, writeKeyword);
2360            writeSpace();
2361
2362            const parenthesizerRule = node.operator === SyntaxKind.ReadonlyKeyword ?
2363                parenthesizer.parenthesizeOperandOfReadonlyTypeOperator :
2364                parenthesizer.parenthesizeOperandOfTypeOperator;
2365            emit(node.type, parenthesizerRule);
2366        }
2367
2368        function emitIndexedAccessType(node: IndexedAccessTypeNode) {
2369            emit(node.objectType, parenthesizer.parenthesizeNonArrayTypeOfPostfixType);
2370            writePunctuation("[");
2371            emit(node.indexType);
2372            writePunctuation("]");
2373        }
2374
2375        function emitMappedType(node: MappedTypeNode) {
2376            const emitFlags = getEmitFlags(node);
2377            writePunctuation("{");
2378            if (emitFlags & EmitFlags.SingleLine) {
2379                writeSpace();
2380            }
2381            else {
2382                writeLine();
2383                increaseIndent();
2384            }
2385            if (node.readonlyToken) {
2386                emit(node.readonlyToken);
2387                if (node.readonlyToken.kind !== SyntaxKind.ReadonlyKeyword) {
2388                    writeKeyword("readonly");
2389                }
2390                writeSpace();
2391            }
2392            writePunctuation("[");
2393
2394            pipelineEmit(EmitHint.MappedTypeParameter, node.typeParameter);
2395            if (node.nameType) {
2396                writeSpace();
2397                writeKeyword("as");
2398                writeSpace();
2399                emit(node.nameType);
2400            }
2401
2402            writePunctuation("]");
2403            if (node.questionToken) {
2404                emit(node.questionToken);
2405                if (node.questionToken.kind !== SyntaxKind.QuestionToken) {
2406                    writePunctuation("?");
2407                }
2408            }
2409            writePunctuation(":");
2410            writeSpace();
2411            emit(node.type);
2412            writeTrailingSemicolon();
2413            if (emitFlags & EmitFlags.SingleLine) {
2414                writeSpace();
2415            }
2416            else {
2417                writeLine();
2418                decreaseIndent();
2419            }
2420            emitList(node, node.members, ListFormat.PreserveLines);
2421            writePunctuation("}");
2422        }
2423
2424        function emitLiteralType(node: LiteralTypeNode) {
2425            emitExpression(node.literal);
2426        }
2427
2428        function emitTemplateType(node: TemplateLiteralTypeNode) {
2429            emit(node.head);
2430            emitList(node, node.templateSpans, ListFormat.TemplateExpressionSpans);
2431        }
2432
2433        function emitImportTypeNode(node: ImportTypeNode) {
2434            if (node.isTypeOf) {
2435                writeKeyword("typeof");
2436                writeSpace();
2437            }
2438            writeKeyword("import");
2439            writePunctuation("(");
2440            emit(node.argument);
2441            if (node.assertions) {
2442                writePunctuation(",");
2443                writeSpace();
2444                writePunctuation("{");
2445                writeSpace();
2446                writeKeyword("assert");
2447                writePunctuation(":");
2448                writeSpace();
2449                const elements = node.assertions.assertClause.elements;
2450                emitList(node.assertions.assertClause, elements, ListFormat.ImportClauseEntries);
2451                writeSpace();
2452                writePunctuation("}");
2453            }
2454            writePunctuation(")");
2455            if (node.qualifier) {
2456                writePunctuation(".");
2457                emit(node.qualifier);
2458            }
2459            emitTypeArguments(node, node.typeArguments);
2460        }
2461
2462        //
2463        // Binding patterns
2464        //
2465
2466        function emitObjectBindingPattern(node: ObjectBindingPattern) {
2467            writePunctuation("{");
2468            emitList(node, node.elements, ListFormat.ObjectBindingPatternElements);
2469            writePunctuation("}");
2470        }
2471
2472        function emitArrayBindingPattern(node: ArrayBindingPattern) {
2473            writePunctuation("[");
2474            emitList(node, node.elements, ListFormat.ArrayBindingPatternElements);
2475            writePunctuation("]");
2476        }
2477
2478        function emitBindingElement(node: BindingElement) {
2479            emit(node.dotDotDotToken);
2480            if (node.propertyName) {
2481                emit(node.propertyName);
2482                writePunctuation(":");
2483                writeSpace();
2484            }
2485            emit(node.name);
2486            emitInitializer(node.initializer, node.name.end, node, parenthesizer.parenthesizeExpressionForDisallowedComma);
2487        }
2488
2489        //
2490        // Expressions
2491        //
2492
2493        function emitArrayLiteralExpression(node: ArrayLiteralExpression) {
2494            const elements = node.elements;
2495            const preferNewLine = node.multiLine ? ListFormat.PreferNewLine : ListFormat.None;
2496            emitExpressionList(node, elements, ListFormat.ArrayLiteralExpressionElements | preferNewLine, parenthesizer.parenthesizeExpressionForDisallowedComma);
2497        }
2498
2499        function emitObjectLiteralExpression(node: ObjectLiteralExpression) {
2500            forEach(node.properties, generateMemberNames);
2501
2502            const indentedFlag = getEmitFlags(node) & EmitFlags.Indented;
2503            if (indentedFlag) {
2504                increaseIndent();
2505            }
2506
2507            const preferNewLine = node.multiLine ? ListFormat.PreferNewLine : ListFormat.None;
2508            const allowTrailingComma = currentSourceFile && currentSourceFile.languageVersion >= ScriptTarget.ES5 && !isJsonSourceFile(currentSourceFile) ? ListFormat.AllowTrailingComma : ListFormat.None;
2509            emitList(node, node.properties, ListFormat.ObjectLiteralExpressionProperties | allowTrailingComma | preferNewLine);
2510
2511            if (indentedFlag) {
2512                decreaseIndent();
2513            }
2514        }
2515
2516        function emitPropertyAccessExpression(node: PropertyAccessExpression) {
2517            emitExpression(node.expression, parenthesizer.parenthesizeLeftSideOfAccess);
2518            const token = node.questionDotToken || setTextRangePosEnd(factory.createToken(SyntaxKind.DotToken) as DotToken, node.expression.end, node.name.pos);
2519            const linesBeforeDot = getLinesBetweenNodes(node, node.expression, token);
2520            const linesAfterDot = getLinesBetweenNodes(node, token, node.name);
2521
2522            writeLinesAndIndent(linesBeforeDot, /*writeSpaceIfNotIndenting*/ false);
2523
2524            const shouldEmitDotDot =
2525                token.kind !== SyntaxKind.QuestionDotToken &&
2526                mayNeedDotDotForPropertyAccess(node.expression) &&
2527                !writer.hasTrailingComment() &&
2528                !writer.hasTrailingWhitespace();
2529
2530            if (shouldEmitDotDot) {
2531                writePunctuation(".");
2532            }
2533
2534            if (node.questionDotToken) {
2535                emit(token);
2536            }
2537            else {
2538                emitTokenWithComment(token.kind, node.expression.end, writePunctuation, node);
2539            }
2540            writeLinesAndIndent(linesAfterDot, /*writeSpaceIfNotIndenting*/ false);
2541            emit(node.name);
2542            decreaseIndentIf(linesBeforeDot, linesAfterDot);
2543        }
2544
2545        // 1..toString is a valid property access, emit a dot after the literal
2546        // Also emit a dot if expression is a integer const enum value - it will appear in generated code as numeric literal
2547        function mayNeedDotDotForPropertyAccess(expression: Expression) {
2548            expression = skipPartiallyEmittedExpressions(expression);
2549            if (isNumericLiteral(expression)) {
2550                // check if numeric literal is a decimal literal that was originally written with a dot
2551                const text = getLiteralTextOfNode(expression as LiteralExpression, /*neverAsciiEscape*/ true, /*jsxAttributeEscape*/ false);
2552                // If he number will be printed verbatim and it doesn't already contain a dot, add one
2553                // if the expression doesn't have any comments that will be emitted.
2554                return !expression.numericLiteralFlags && !stringContains(text, tokenToString(SyntaxKind.DotToken)!);
2555            }
2556            else if (isAccessExpression(expression)) {
2557                // check if constant enum value is integer
2558                const constantValue = getConstantValue(expression);
2559                // isFinite handles cases when constantValue is undefined
2560                return typeof constantValue === "number" && isFinite(constantValue)
2561                    && Math.floor(constantValue) === constantValue;
2562            }
2563        }
2564
2565        function emitElementAccessExpression(node: ElementAccessExpression) {
2566            emitExpression(node.expression, parenthesizer.parenthesizeLeftSideOfAccess);
2567            emit(node.questionDotToken);
2568            emitTokenWithComment(SyntaxKind.OpenBracketToken, node.expression.end, writePunctuation, node);
2569            emitExpression(node.argumentExpression);
2570            emitTokenWithComment(SyntaxKind.CloseBracketToken, node.argumentExpression.end, writePunctuation, node);
2571        }
2572
2573        function emitCallExpression(node: CallExpression) {
2574            const indirectCall = getEmitFlags(node) & EmitFlags.IndirectCall;
2575            if (indirectCall) {
2576                writePunctuation("(");
2577                writeLiteral("0");
2578                writePunctuation(",");
2579                writeSpace();
2580            }
2581            emitExpression(node.expression, parenthesizer.parenthesizeLeftSideOfAccess);
2582            if (indirectCall) {
2583                writePunctuation(")");
2584            }
2585            emit(node.questionDotToken);
2586            emitTypeArguments(node, node.typeArguments);
2587            emitExpressionList(node, node.arguments, ListFormat.CallExpressionArguments, parenthesizer.parenthesizeExpressionForDisallowedComma);
2588        }
2589
2590        function emitNewExpression(node: NewExpression) {
2591            emitTokenWithComment(SyntaxKind.NewKeyword, node.pos, writeKeyword, node);
2592            writeSpace();
2593            emitExpression(node.expression, parenthesizer.parenthesizeExpressionOfNew);
2594            emitTypeArguments(node, node.typeArguments);
2595            emitExpressionList(node, node.arguments, ListFormat.NewExpressionArguments, parenthesizer.parenthesizeExpressionForDisallowedComma);
2596        }
2597
2598        function emitTaggedTemplateExpression(node: TaggedTemplateExpression) {
2599            const indirectCall = getEmitFlags(node) & EmitFlags.IndirectCall;
2600            if (indirectCall) {
2601                writePunctuation("(");
2602                writeLiteral("0");
2603                writePunctuation(",");
2604                writeSpace();
2605            }
2606            emitExpression(node.tag, parenthesizer.parenthesizeLeftSideOfAccess);
2607            if (indirectCall) {
2608                writePunctuation(")");
2609            }
2610            emitTypeArguments(node, node.typeArguments);
2611            writeSpace();
2612            emitExpression(node.template);
2613        }
2614
2615        function emitTypeAssertionExpression(node: TypeAssertion) {
2616            writePunctuation("<");
2617            emit(node.type);
2618            writePunctuation(">");
2619            emitExpression(node.expression, parenthesizer.parenthesizeOperandOfPrefixUnary);
2620        }
2621
2622        function emitParenthesizedExpression(node: ParenthesizedExpression) {
2623            const openParenPos = emitTokenWithComment(SyntaxKind.OpenParenToken, node.pos, writePunctuation, node);
2624            const indented = writeLineSeparatorsAndIndentBefore(node.expression, node);
2625            emitExpression(node.expression, /*parenthesizerRules*/ undefined);
2626            writeLineSeparatorsAfter(node.expression, node);
2627            decreaseIndentIf(indented);
2628            emitTokenWithComment(SyntaxKind.CloseParenToken, node.expression ? node.expression.end : openParenPos, writePunctuation, node);
2629        }
2630
2631        function emitFunctionExpression(node: FunctionExpression) {
2632            generateNameIfNeeded(node.name);
2633            emitFunctionDeclarationOrExpression(node);
2634        }
2635
2636        function emitArrowFunction(node: ArrowFunction) {
2637            emitModifiers(node, node.modifiers);
2638            emitSignatureAndBody(node, emitArrowFunctionHead);
2639        }
2640
2641        function emitArrowFunctionHead(node: ArrowFunction) {
2642            emitTypeParameters(node, node.typeParameters);
2643            emitParametersForArrow(node, node.parameters);
2644            emitTypeAnnotation(node.type);
2645            writeSpace();
2646            emit(node.equalsGreaterThanToken);
2647        }
2648
2649        function emitDeleteExpression(node: DeleteExpression) {
2650            emitTokenWithComment(SyntaxKind.DeleteKeyword, node.pos, writeKeyword, node);
2651            writeSpace();
2652            emitExpression(node.expression, parenthesizer.parenthesizeOperandOfPrefixUnary);
2653        }
2654
2655        function emitTypeOfExpression(node: TypeOfExpression) {
2656            emitTokenWithComment(SyntaxKind.TypeOfKeyword, node.pos, writeKeyword, node);
2657            writeSpace();
2658            emitExpression(node.expression, parenthesizer.parenthesizeOperandOfPrefixUnary);
2659        }
2660
2661        function emitVoidExpression(node: VoidExpression) {
2662            emitTokenWithComment(SyntaxKind.VoidKeyword, node.pos, writeKeyword, node);
2663            writeSpace();
2664            emitExpression(node.expression, parenthesizer.parenthesizeOperandOfPrefixUnary);
2665        }
2666
2667        function emitAwaitExpression(node: AwaitExpression) {
2668            emitTokenWithComment(SyntaxKind.AwaitKeyword, node.pos, writeKeyword, node);
2669            writeSpace();
2670            emitExpression(node.expression, parenthesizer.parenthesizeOperandOfPrefixUnary);
2671        }
2672
2673        function emitPrefixUnaryExpression(node: PrefixUnaryExpression) {
2674            writeTokenText(node.operator, writeOperator);
2675            if (shouldEmitWhitespaceBeforeOperand(node)) {
2676                writeSpace();
2677            }
2678            emitExpression(node.operand, parenthesizer.parenthesizeOperandOfPrefixUnary);
2679        }
2680
2681        function shouldEmitWhitespaceBeforeOperand(node: PrefixUnaryExpression) {
2682            // In some cases, we need to emit a space between the operator and the operand. One obvious case
2683            // is when the operator is an identifier, like delete or typeof. We also need to do this for plus
2684            // and minus expressions in certain cases. Specifically, consider the following two cases (parens
2685            // are just for clarity of exposition, and not part of the source code):
2686            //
2687            //  (+(+1))
2688            //  (+(++1))
2689            //
2690            // We need to emit a space in both cases. In the first case, the absence of a space will make
2691            // the resulting expression a prefix increment operation. And in the second, it will make the resulting
2692            // expression a prefix increment whose operand is a plus expression - (++(+x))
2693            // The same is true of minus of course.
2694            const operand = node.operand;
2695            return operand.kind === SyntaxKind.PrefixUnaryExpression
2696                && ((node.operator === SyntaxKind.PlusToken && ((operand as PrefixUnaryExpression).operator === SyntaxKind.PlusToken || (operand as PrefixUnaryExpression).operator === SyntaxKind.PlusPlusToken))
2697                    || (node.operator === SyntaxKind.MinusToken && ((operand as PrefixUnaryExpression).operator === SyntaxKind.MinusToken || (operand as PrefixUnaryExpression).operator === SyntaxKind.MinusMinusToken)));
2698        }
2699
2700        function emitPostfixUnaryExpression(node: PostfixUnaryExpression) {
2701            emitExpression(node.operand, parenthesizer.parenthesizeOperandOfPostfixUnary);
2702            writeTokenText(node.operator, writeOperator);
2703        }
2704
2705        function createEmitBinaryExpression() {
2706            interface WorkArea {
2707                stackIndex: number;
2708                preserveSourceNewlinesStack: (boolean | undefined)[];
2709                containerPosStack: number[];
2710                containerEndStack: number[];
2711                declarationListContainerEndStack: number[];
2712                shouldEmitCommentsStack: boolean[];
2713                shouldEmitSourceMapsStack: boolean[];
2714            }
2715
2716            return createBinaryExpressionTrampoline(onEnter, onLeft, onOperator, onRight, onExit, /*foldState*/ undefined);
2717
2718            function onEnter(node: BinaryExpression, state: WorkArea | undefined) {
2719                if (state) {
2720                    state.stackIndex++;
2721                    state.preserveSourceNewlinesStack[state.stackIndex] = preserveSourceNewlines;
2722                    state.containerPosStack[state.stackIndex] = containerPos;
2723                    state.containerEndStack[state.stackIndex] = containerEnd;
2724                    state.declarationListContainerEndStack[state.stackIndex] = declarationListContainerEnd;
2725                    const emitComments = state.shouldEmitCommentsStack[state.stackIndex] = shouldEmitComments(node);
2726                    const emitSourceMaps = state.shouldEmitSourceMapsStack[state.stackIndex] = shouldEmitSourceMaps(node);
2727                    onBeforeEmitNode?.(node);
2728                    if (emitComments) emitCommentsBeforeNode(node);
2729                    if (emitSourceMaps) emitSourceMapsBeforeNode(node);
2730                    beforeEmitNode(node);
2731                }
2732                else {
2733                    state = {
2734                        stackIndex: 0,
2735                        preserveSourceNewlinesStack: [undefined],
2736                        containerPosStack: [-1],
2737                        containerEndStack: [-1],
2738                        declarationListContainerEndStack: [-1],
2739                        shouldEmitCommentsStack: [false],
2740                        shouldEmitSourceMapsStack: [false],
2741                    };
2742                }
2743                return state;
2744            }
2745
2746            function onLeft(next: Expression, _workArea: WorkArea, parent: BinaryExpression) {
2747                return maybeEmitExpression(next, parent, "left");
2748            }
2749
2750            function onOperator(operatorToken: BinaryOperatorToken, _state: WorkArea, node: BinaryExpression) {
2751                const isCommaOperator = operatorToken.kind !== SyntaxKind.CommaToken;
2752                const linesBeforeOperator = getLinesBetweenNodes(node, node.left, operatorToken);
2753                const linesAfterOperator = getLinesBetweenNodes(node, operatorToken, node.right);
2754                writeLinesAndIndent(linesBeforeOperator, isCommaOperator);
2755                emitLeadingCommentsOfPosition(operatorToken.pos);
2756                writeTokenNode(operatorToken, operatorToken.kind === SyntaxKind.InKeyword ? writeKeyword : writeOperator);
2757                emitTrailingCommentsOfPosition(operatorToken.end, /*prefixSpace*/ true); // Binary operators should have a space before the comment starts
2758                writeLinesAndIndent(linesAfterOperator, /*writeSpaceIfNotIndenting*/ true);
2759            }
2760
2761            function onRight(next: Expression, _workArea: WorkArea, parent: BinaryExpression) {
2762                return maybeEmitExpression(next, parent, "right");
2763            }
2764
2765            function onExit(node: BinaryExpression, state: WorkArea) {
2766                const linesBeforeOperator = getLinesBetweenNodes(node, node.left, node.operatorToken);
2767                const linesAfterOperator = getLinesBetweenNodes(node, node.operatorToken, node.right);
2768                decreaseIndentIf(linesBeforeOperator, linesAfterOperator);
2769                if (state.stackIndex > 0) {
2770                    const savedPreserveSourceNewlines = state.preserveSourceNewlinesStack[state.stackIndex];
2771                    const savedContainerPos = state.containerPosStack[state.stackIndex];
2772                    const savedContainerEnd = state.containerEndStack[state.stackIndex];
2773                    const savedDeclarationListContainerEnd = state.declarationListContainerEndStack[state.stackIndex];
2774                    const shouldEmitComments = state.shouldEmitCommentsStack[state.stackIndex];
2775                    const shouldEmitSourceMaps = state.shouldEmitSourceMapsStack[state.stackIndex];
2776                    afterEmitNode(savedPreserveSourceNewlines);
2777                    if (shouldEmitSourceMaps) emitSourceMapsAfterNode(node);
2778                    if (shouldEmitComments) emitCommentsAfterNode(node, savedContainerPos, savedContainerEnd, savedDeclarationListContainerEnd);
2779                    onAfterEmitNode?.(node);
2780                    state.stackIndex--;
2781                }
2782            }
2783
2784            function maybeEmitExpression(next: Expression, parent: BinaryExpression, side: "left" | "right") {
2785                const parenthesizerRule = side === "left" ?
2786                    parenthesizer.getParenthesizeLeftSideOfBinaryForOperator(parent.operatorToken.kind) :
2787                    parenthesizer.getParenthesizeRightSideOfBinaryForOperator(parent.operatorToken.kind);
2788
2789                let pipelinePhase = getPipelinePhase(PipelinePhase.Notification, EmitHint.Expression, next);
2790                if (pipelinePhase === pipelineEmitWithSubstitution) {
2791                    Debug.assertIsDefined(lastSubstitution);
2792                    next = parenthesizerRule(cast(lastSubstitution, isExpression));
2793                    pipelinePhase = getNextPipelinePhase(PipelinePhase.Substitution, EmitHint.Expression, next);
2794                    lastSubstitution = undefined;
2795                }
2796
2797                if (pipelinePhase === pipelineEmitWithComments ||
2798                    pipelinePhase === pipelineEmitWithSourceMaps ||
2799                    pipelinePhase === pipelineEmitWithHint) {
2800                    if (isBinaryExpression(next)) {
2801                        return next;
2802                    }
2803                }
2804
2805                currentParenthesizerRule = parenthesizerRule;
2806                pipelinePhase(EmitHint.Expression, next);
2807            }
2808        }
2809
2810        function emitConditionalExpression(node: ConditionalExpression) {
2811            const linesBeforeQuestion = getLinesBetweenNodes(node, node.condition, node.questionToken);
2812            const linesAfterQuestion = getLinesBetweenNodes(node, node.questionToken, node.whenTrue);
2813            const linesBeforeColon = getLinesBetweenNodes(node, node.whenTrue, node.colonToken);
2814            const linesAfterColon = getLinesBetweenNodes(node, node.colonToken, node.whenFalse);
2815
2816            emitExpression(node.condition, parenthesizer.parenthesizeConditionOfConditionalExpression);
2817            writeLinesAndIndent(linesBeforeQuestion, /*writeSpaceIfNotIndenting*/ true);
2818            emit(node.questionToken);
2819            writeLinesAndIndent(linesAfterQuestion, /*writeSpaceIfNotIndenting*/ true);
2820            emitExpression(node.whenTrue, parenthesizer.parenthesizeBranchOfConditionalExpression);
2821            decreaseIndentIf(linesBeforeQuestion, linesAfterQuestion);
2822
2823            writeLinesAndIndent(linesBeforeColon, /*writeSpaceIfNotIndenting*/ true);
2824            emit(node.colonToken);
2825            writeLinesAndIndent(linesAfterColon, /*writeSpaceIfNotIndenting*/ true);
2826            emitExpression(node.whenFalse, parenthesizer.parenthesizeBranchOfConditionalExpression);
2827            decreaseIndentIf(linesBeforeColon, linesAfterColon);
2828        }
2829
2830        function emitTemplateExpression(node: TemplateExpression) {
2831            emit(node.head);
2832            emitList(node, node.templateSpans, ListFormat.TemplateExpressionSpans);
2833        }
2834
2835        function emitYieldExpression(node: YieldExpression) {
2836            emitTokenWithComment(SyntaxKind.YieldKeyword, node.pos, writeKeyword, node);
2837            emit(node.asteriskToken);
2838            emitExpressionWithLeadingSpace(node.expression && parenthesizeExpressionForNoAsi(node.expression), parenthesizeExpressionForNoAsiAndDisallowedComma);
2839        }
2840
2841        function emitSpreadElement(node: SpreadElement) {
2842            emitTokenWithComment(SyntaxKind.DotDotDotToken, node.pos, writePunctuation, node);
2843            emitExpression(node.expression, parenthesizer.parenthesizeExpressionForDisallowedComma);
2844        }
2845
2846        function emitClassExpression(node: ClassExpression) {
2847            generateNameIfNeeded(node.name);
2848            emitClassOrStructDeclarationOrExpression(node);
2849        }
2850
2851        function emitExpressionWithTypeArguments(node: ExpressionWithTypeArguments) {
2852            emitExpression(node.expression, parenthesizer.parenthesizeLeftSideOfAccess);
2853            emitTypeArguments(node, node.typeArguments);
2854        }
2855
2856        function emitAsExpression(node: AsExpression) {
2857            emitExpression(node.expression, /*parenthesizerRules*/ undefined);
2858            if (node.type) {
2859                writeSpace();
2860                writeKeyword("as");
2861                writeSpace();
2862                emit(node.type);
2863            }
2864        }
2865
2866        function emitNonNullExpression(node: NonNullExpression) {
2867            emitExpression(node.expression, parenthesizer.parenthesizeLeftSideOfAccess);
2868            writeOperator("!");
2869        }
2870
2871        function emitSatisfiesExpression(node: SatisfiesExpression) {
2872            emitExpression(node.expression, /*parenthesizerRules*/ undefined);
2873            if (node.type) {
2874                writeSpace();
2875                writeKeyword("satisfies");
2876                writeSpace();
2877                emit(node.type);
2878            }
2879        }
2880
2881        function emitMetaProperty(node: MetaProperty) {
2882            writeToken(node.keywordToken, node.pos, writePunctuation);
2883            writePunctuation(".");
2884            emit(node.name);
2885        }
2886
2887        //
2888        // Misc
2889        //
2890
2891        function emitTemplateSpan(node: TemplateSpan) {
2892            emitExpression(node.expression);
2893            emit(node.literal);
2894        }
2895
2896        //
2897        // Statements
2898        //
2899
2900        function emitBlock(node: Block) {
2901            emitBlockStatements(node, /*forceSingleLine*/ !node.multiLine && isEmptyBlock(node));
2902        }
2903
2904        function emitBlockStatements(node: BlockLike, forceSingleLine: boolean) {
2905            emitTokenWithComment(SyntaxKind.OpenBraceToken, node.pos, writePunctuation, /*contextNode*/ node);
2906            const format = forceSingleLine || getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineBlockStatements : ListFormat.MultiLineBlockStatements;
2907            emitList(node, node.statements, format);
2908            emitTokenWithComment(SyntaxKind.CloseBraceToken, node.statements.end, writePunctuation, /*contextNode*/ node, /*indentLeading*/ !!(format & ListFormat.MultiLine));
2909        }
2910
2911        function emitVariableStatement(node: VariableStatement) {
2912            emitModifiers(node, node.modifiers);
2913            emit(node.declarationList);
2914            writeTrailingSemicolon();
2915        }
2916
2917        function emitEmptyStatement(isEmbeddedStatement: boolean) {
2918            // While most trailing semicolons are possibly insignificant, an embedded "empty"
2919            // statement is significant and cannot be elided by a trailing-semicolon-omitting writer.
2920            if (isEmbeddedStatement) {
2921                writePunctuation(";");
2922            }
2923            else {
2924                writeTrailingSemicolon();
2925            }
2926        }
2927
2928        function emitExpressionStatement(node: ExpressionStatement) {
2929            emitExpression(node.expression, parenthesizer.parenthesizeExpressionOfExpressionStatement);
2930            // Emit semicolon in non json files
2931            // or if json file that created synthesized expression(eg.define expression statement when --out and amd code generation)
2932            if (!currentSourceFile || !isJsonSourceFile(currentSourceFile) || nodeIsSynthesized(node.expression)) {
2933                writeTrailingSemicolon();
2934            }
2935        }
2936
2937        function emitIfStatement(node: IfStatement) {
2938            const openParenPos = emitTokenWithComment(SyntaxKind.IfKeyword, node.pos, writeKeyword, node);
2939            writeSpace();
2940            emitTokenWithComment(SyntaxKind.OpenParenToken, openParenPos, writePunctuation, node);
2941            emitExpression(node.expression);
2942            emitTokenWithComment(SyntaxKind.CloseParenToken, node.expression.end, writePunctuation, node);
2943            emitEmbeddedStatement(node, node.thenStatement);
2944            if (node.elseStatement) {
2945                writeLineOrSpace(node, node.thenStatement, node.elseStatement);
2946                emitTokenWithComment(SyntaxKind.ElseKeyword, node.thenStatement.end, writeKeyword, node);
2947                if (node.elseStatement.kind === SyntaxKind.IfStatement) {
2948                    writeSpace();
2949                    emit(node.elseStatement);
2950                }
2951                else {
2952                    emitEmbeddedStatement(node, node.elseStatement);
2953                }
2954            }
2955        }
2956
2957        function emitWhileClause(node: WhileStatement | DoStatement, startPos: number) {
2958            const openParenPos = emitTokenWithComment(SyntaxKind.WhileKeyword, startPos, writeKeyword, node);
2959            writeSpace();
2960            emitTokenWithComment(SyntaxKind.OpenParenToken, openParenPos, writePunctuation, node);
2961            emitExpression(node.expression);
2962            emitTokenWithComment(SyntaxKind.CloseParenToken, node.expression.end, writePunctuation, node);
2963        }
2964
2965        function emitDoStatement(node: DoStatement) {
2966            emitTokenWithComment(SyntaxKind.DoKeyword, node.pos, writeKeyword, node);
2967            emitEmbeddedStatement(node, node.statement);
2968            if (isBlock(node.statement) && !preserveSourceNewlines) {
2969                writeSpace();
2970            }
2971            else {
2972                writeLineOrSpace(node, node.statement, node.expression);
2973            }
2974
2975            emitWhileClause(node, node.statement.end);
2976            writeTrailingSemicolon();
2977        }
2978
2979        function emitWhileStatement(node: WhileStatement) {
2980            emitWhileClause(node, node.pos);
2981            emitEmbeddedStatement(node, node.statement);
2982        }
2983
2984        function emitForStatement(node: ForStatement) {
2985            const openParenPos = emitTokenWithComment(SyntaxKind.ForKeyword, node.pos, writeKeyword, node);
2986            writeSpace();
2987            let pos = emitTokenWithComment(SyntaxKind.OpenParenToken, openParenPos, writePunctuation, /*contextNode*/ node);
2988            emitForBinding(node.initializer);
2989            pos = emitTokenWithComment(SyntaxKind.SemicolonToken, node.initializer ? node.initializer.end : pos, writePunctuation, node);
2990            emitExpressionWithLeadingSpace(node.condition);
2991            pos = emitTokenWithComment(SyntaxKind.SemicolonToken, node.condition ? node.condition.end : pos, writePunctuation, node);
2992            emitExpressionWithLeadingSpace(node.incrementor);
2993            emitTokenWithComment(SyntaxKind.CloseParenToken, node.incrementor ? node.incrementor.end : pos, writePunctuation, node);
2994            emitEmbeddedStatement(node, node.statement);
2995        }
2996
2997        function emitForInStatement(node: ForInStatement) {
2998            const openParenPos = emitTokenWithComment(SyntaxKind.ForKeyword, node.pos, writeKeyword, node);
2999            writeSpace();
3000            emitTokenWithComment(SyntaxKind.OpenParenToken, openParenPos, writePunctuation, node);
3001            emitForBinding(node.initializer);
3002            writeSpace();
3003            emitTokenWithComment(SyntaxKind.InKeyword, node.initializer.end, writeKeyword, node);
3004            writeSpace();
3005            emitExpression(node.expression);
3006            emitTokenWithComment(SyntaxKind.CloseParenToken, node.expression.end, writePunctuation, node);
3007            emitEmbeddedStatement(node, node.statement);
3008        }
3009
3010        function emitForOfStatement(node: ForOfStatement) {
3011            const openParenPos = emitTokenWithComment(SyntaxKind.ForKeyword, node.pos, writeKeyword, node);
3012            writeSpace();
3013            emitWithTrailingSpace(node.awaitModifier);
3014            emitTokenWithComment(SyntaxKind.OpenParenToken, openParenPos, writePunctuation, node);
3015            emitForBinding(node.initializer);
3016            writeSpace();
3017            emitTokenWithComment(SyntaxKind.OfKeyword, node.initializer.end, writeKeyword, node);
3018            writeSpace();
3019            emitExpression(node.expression);
3020            emitTokenWithComment(SyntaxKind.CloseParenToken, node.expression.end, writePunctuation, node);
3021            emitEmbeddedStatement(node, node.statement);
3022        }
3023
3024        function emitForBinding(node: VariableDeclarationList | Expression | undefined) {
3025            if (node !== undefined) {
3026                if (node.kind === SyntaxKind.VariableDeclarationList) {
3027                    emit(node);
3028                }
3029                else {
3030                    emitExpression(node);
3031                }
3032            }
3033        }
3034
3035        function emitContinueStatement(node: ContinueStatement) {
3036            emitTokenWithComment(SyntaxKind.ContinueKeyword, node.pos, writeKeyword, node);
3037            emitWithLeadingSpace(node.label);
3038            writeTrailingSemicolon();
3039        }
3040
3041        function emitBreakStatement(node: BreakStatement) {
3042            emitTokenWithComment(SyntaxKind.BreakKeyword, node.pos, writeKeyword, node);
3043            emitWithLeadingSpace(node.label);
3044            writeTrailingSemicolon();
3045        }
3046
3047        function emitTokenWithComment(token: SyntaxKind, pos: number, writer: (s: string) => void, contextNode: Node, indentLeading?: boolean) {
3048            const node = getParseTreeNode(contextNode);
3049            const isSimilarNode = node && node.kind === contextNode.kind;
3050            const startPos = pos;
3051            if (isSimilarNode && currentSourceFile) {
3052                pos = skipTrivia(currentSourceFile.text, pos);
3053            }
3054            if (isSimilarNode && contextNode.pos !== startPos) {
3055                const needsIndent = indentLeading && currentSourceFile && !positionsAreOnSameLine(startPos, pos, currentSourceFile);
3056                if (needsIndent) {
3057                    increaseIndent();
3058                }
3059                emitLeadingCommentsOfPosition(startPos);
3060                if (needsIndent) {
3061                    decreaseIndent();
3062                }
3063            }
3064            pos = writeTokenText(token, writer, pos);
3065            if (isSimilarNode && contextNode.end !== pos) {
3066                const isJsxExprContext = contextNode.kind === SyntaxKind.JsxExpression;
3067                emitTrailingCommentsOfPosition(pos, /*prefixSpace*/ !isJsxExprContext, /*forceNoNewline*/ isJsxExprContext);
3068            }
3069            return pos;
3070        }
3071
3072        function commentWillEmitNewLine(node: CommentRange) {
3073            return node.kind === SyntaxKind.SingleLineCommentTrivia || !!node.hasTrailingNewLine;
3074        }
3075
3076        function willEmitLeadingNewLine(node: Expression): boolean {
3077            if (!currentSourceFile) return false;
3078            if (some(getLeadingCommentRanges(currentSourceFile.text, node.pos), commentWillEmitNewLine)) return true;
3079            if (some(getSyntheticLeadingComments(node), commentWillEmitNewLine)) return true;
3080            if (isPartiallyEmittedExpression(node)) {
3081                if (node.pos !== node.expression.pos) {
3082                    if (some(getTrailingCommentRanges(currentSourceFile.text, node.expression.pos), commentWillEmitNewLine)) return true;
3083                }
3084                return willEmitLeadingNewLine(node.expression);
3085            }
3086            return false;
3087        }
3088
3089        /**
3090         * Wraps an expression in parens if we would emit a leading comment that would introduce a line separator
3091         * between the node and its parent.
3092         */
3093        function parenthesizeExpressionForNoAsi(node: Expression) {
3094            if (!commentsDisabled && isPartiallyEmittedExpression(node) && willEmitLeadingNewLine(node)) {
3095                const parseNode = getParseTreeNode(node);
3096                if (parseNode && isParenthesizedExpression(parseNode)) {
3097                    // If the original node was a parenthesized expression, restore it to preserve comment and source map emit
3098                    const parens = factory.createParenthesizedExpression(node.expression);
3099                    setOriginalNode(parens, node);
3100                    setTextRange(parens, parseNode);
3101                    return parens;
3102                }
3103                return factory.createParenthesizedExpression(node);
3104            }
3105            return node;
3106        }
3107
3108        function parenthesizeExpressionForNoAsiAndDisallowedComma(node: Expression) {
3109            return parenthesizeExpressionForNoAsi(parenthesizer.parenthesizeExpressionForDisallowedComma(node));
3110        }
3111
3112        function emitReturnStatement(node: ReturnStatement) {
3113            emitTokenWithComment(SyntaxKind.ReturnKeyword, node.pos, writeKeyword, /*contextNode*/ node);
3114            emitExpressionWithLeadingSpace(node.expression && parenthesizeExpressionForNoAsi(node.expression), parenthesizeExpressionForNoAsi);
3115            writeTrailingSemicolon();
3116        }
3117
3118        function emitWithStatement(node: WithStatement) {
3119            const openParenPos = emitTokenWithComment(SyntaxKind.WithKeyword, node.pos, writeKeyword, node);
3120            writeSpace();
3121            emitTokenWithComment(SyntaxKind.OpenParenToken, openParenPos, writePunctuation, node);
3122            emitExpression(node.expression);
3123            emitTokenWithComment(SyntaxKind.CloseParenToken, node.expression.end, writePunctuation, node);
3124            emitEmbeddedStatement(node, node.statement);
3125        }
3126
3127        function emitSwitchStatement(node: SwitchStatement) {
3128            const openParenPos = emitTokenWithComment(SyntaxKind.SwitchKeyword, node.pos, writeKeyword, node);
3129            writeSpace();
3130            emitTokenWithComment(SyntaxKind.OpenParenToken, openParenPos, writePunctuation, node);
3131            emitExpression(node.expression);
3132            emitTokenWithComment(SyntaxKind.CloseParenToken, node.expression.end, writePunctuation, node);
3133            writeSpace();
3134            emit(node.caseBlock);
3135        }
3136
3137        function emitLabeledStatement(node: LabeledStatement) {
3138            emit(node.label);
3139            emitTokenWithComment(SyntaxKind.ColonToken, node.label.end, writePunctuation, node);
3140            writeSpace();
3141            emit(node.statement);
3142        }
3143
3144        function emitThrowStatement(node: ThrowStatement) {
3145            emitTokenWithComment(SyntaxKind.ThrowKeyword, node.pos, writeKeyword, node);
3146            emitExpressionWithLeadingSpace(parenthesizeExpressionForNoAsi(node.expression), parenthesizeExpressionForNoAsi);
3147            writeTrailingSemicolon();
3148        }
3149
3150        function emitTryStatement(node: TryStatement) {
3151            emitTokenWithComment(SyntaxKind.TryKeyword, node.pos, writeKeyword, node);
3152            writeSpace();
3153            emit(node.tryBlock);
3154            if (node.catchClause) {
3155                writeLineOrSpace(node, node.tryBlock, node.catchClause);
3156                emit(node.catchClause);
3157            }
3158            if (node.finallyBlock) {
3159                writeLineOrSpace(node, node.catchClause || node.tryBlock, node.finallyBlock);
3160                emitTokenWithComment(SyntaxKind.FinallyKeyword, (node.catchClause || node.tryBlock).end, writeKeyword, node);
3161                writeSpace();
3162                emit(node.finallyBlock);
3163            }
3164        }
3165
3166        function emitDebuggerStatement(node: DebuggerStatement) {
3167            writeToken(SyntaxKind.DebuggerKeyword, node.pos, writeKeyword);
3168            writeTrailingSemicolon();
3169        }
3170
3171        //
3172        // Declarations
3173        //
3174
3175        function emitVariableDeclaration(node: VariableDeclaration) {
3176            emit(node.name);
3177            emit(node.exclamationToken);
3178            emitTypeAnnotation(node.type);
3179            emitInitializer(node.initializer, node.type?.end ?? node.name.emitNode?.typeNode?.end ?? node.name.end, node, parenthesizer.parenthesizeExpressionForDisallowedComma);
3180        }
3181
3182        function emitVariableDeclarationList(node: VariableDeclarationList) {
3183            writeKeyword(isLet(node) ? "let" : isVarConst(node) ? "const" : "var");
3184            writeSpace();
3185            emitList(node, node.declarations, ListFormat.VariableDeclarationList);
3186        }
3187
3188        function emitFunctionDeclaration(node: FunctionDeclaration) {
3189            emitFunctionDeclarationOrExpression(node);
3190        }
3191
3192        function emitFunctionDeclarationOrExpression(node: FunctionDeclaration | FunctionExpression) {
3193            if (isFunctionDeclaration(node) && (isInEtsFile(node) || isInEtsFileWithOriginal(node))) {
3194                emitDecorators(node, node.illegalDecorators);
3195                getSourceFileOfNode
3196            }
3197            emitModifiers(node, factory.createNodeArray(getModifiers(node)));
3198            writeKeyword("function");
3199            emit(node.asteriskToken);
3200            writeSpace();
3201            emitIdentifierName(node.name);
3202            emitSignatureAndBody(node, emitSignatureHead);
3203        }
3204
3205        function emitSignatureAndBody(node: FunctionLikeDeclaration, emitSignatureHead: (node: SignatureDeclaration) => void) {
3206            const body = node.body;
3207            if (body) {
3208                if (isBlock(body)) {
3209                    const indentedFlag = getEmitFlags(node) & EmitFlags.Indented;
3210                    if (indentedFlag) {
3211                        increaseIndent();
3212                    }
3213
3214                    pushNameGenerationScope(node);
3215                    forEach(node.parameters, generateNames);
3216                    generateNames(node.body);
3217
3218                    emitSignatureHead(node);
3219                    emitBlockFunctionBody(body);
3220                    popNameGenerationScope(node);
3221
3222                    if (indentedFlag) {
3223                        decreaseIndent();
3224                    }
3225                }
3226                else {
3227                    emitSignatureHead(node);
3228                    writeSpace();
3229                    emitExpression(body, parenthesizer.parenthesizeConciseBodyOfArrowFunction);
3230                }
3231            }
3232            else {
3233                emitSignatureHead(node);
3234                writeTrailingSemicolon();
3235            }
3236
3237        }
3238
3239        function emitSignatureHead(node: FunctionDeclaration | FunctionExpression | MethodDeclaration | AccessorDeclaration | ConstructorDeclaration) {
3240            emitTypeParameters(node, node.typeParameters);
3241            emitParameters(node, node.parameters);
3242            emitTypeAnnotation(node.type);
3243        }
3244
3245        function shouldEmitBlockFunctionBodyOnSingleLine(body: Block) {
3246            // We must emit a function body as a single-line body in the following case:
3247            // * The body has NodeEmitFlags.SingleLine specified.
3248
3249            // We must emit a function body as a multi-line body in the following cases:
3250            // * The body is explicitly marked as multi-line.
3251            // * A non-synthesized body's start and end position are on different lines.
3252            // * Any statement in the body starts on a new line.
3253
3254            if (getEmitFlags(body) & EmitFlags.SingleLine) {
3255                return true;
3256            }
3257
3258            if (body.multiLine) {
3259                return false;
3260            }
3261
3262            if (!nodeIsSynthesized(body) && currentSourceFile && !rangeIsOnSingleLine(body, currentSourceFile)) {
3263                return false;
3264            }
3265
3266            if (getLeadingLineTerminatorCount(body, firstOrUndefined(body.statements), ListFormat.PreserveLines)
3267                || getClosingLineTerminatorCount(body, lastOrUndefined(body.statements), ListFormat.PreserveLines, body.statements)) {
3268                return false;
3269            }
3270
3271            let previousStatement: Statement | undefined;
3272            for (const statement of body.statements) {
3273                if (getSeparatingLineTerminatorCount(previousStatement, statement, ListFormat.PreserveLines) > 0) {
3274                    return false;
3275                }
3276
3277                previousStatement = statement;
3278            }
3279
3280            return true;
3281        }
3282
3283        function emitBlockFunctionBody(body: Block) {
3284            onBeforeEmitNode?.(body);
3285            writeSpace();
3286            writePunctuation("{");
3287            increaseIndent();
3288
3289            const emitBlockFunctionBody = shouldEmitBlockFunctionBodyOnSingleLine(body)
3290                ? emitBlockFunctionBodyOnSingleLine
3291                : emitBlockFunctionBodyWorker;
3292
3293            emitBodyWithDetachedComments(body, body.statements, emitBlockFunctionBody);
3294
3295            decreaseIndent();
3296            writeToken(SyntaxKind.CloseBraceToken, body.statements.end, writePunctuation, body);
3297            onAfterEmitNode?.(body);
3298        }
3299
3300        function emitBlockFunctionBodyOnSingleLine(body: Block) {
3301            emitBlockFunctionBodyWorker(body, /*emitBlockFunctionBodyOnSingleLine*/ true);
3302        }
3303
3304        function emitBlockFunctionBodyWorker(body: Block, emitBlockFunctionBodyOnSingleLine?: boolean) {
3305            // Emit all the prologue directives (like "use strict").
3306            const statementOffset = emitPrologueDirectives(body.statements);
3307            const pos = writer.getTextPos();
3308            emitHelpers(body);
3309            if (statementOffset === 0 && pos === writer.getTextPos() && emitBlockFunctionBodyOnSingleLine) {
3310                decreaseIndent();
3311                emitList(body, body.statements, ListFormat.SingleLineFunctionBodyStatements);
3312                increaseIndent();
3313            }
3314            else {
3315                emitList(body, body.statements, ListFormat.MultiLineFunctionBodyStatements, /*parenthesizerRule*/ undefined, statementOffset);
3316            }
3317        }
3318
3319        function emitClassOrStructDeclaration(node: ClassDeclaration | StructDeclaration) {
3320            emitClassOrStructDeclarationOrExpression(node);
3321        }
3322
3323        function emitClassOrStructDeclarationOrExpression(node: ClassDeclaration | ClassExpression | StructDeclaration) {
3324            forEach(node.members, generateMemberNames);
3325
3326            emitDecoratorsAndModifiers(node, node.modifiers);
3327            if (isStructDeclaration(node)) {
3328                writeKeyword("struct");
3329            }
3330            else {
3331                writeKeyword("class");
3332            }
3333            if (node.name) {
3334                writeSpace();
3335                emitIdentifierName(node.name);
3336            }
3337
3338            const indentedFlag = getEmitFlags(node) & EmitFlags.Indented;
3339            if (indentedFlag) {
3340                increaseIndent();
3341            }
3342
3343            emitTypeParameters(node, node.typeParameters);
3344            emitList(node, node.heritageClauses, ListFormat.ClassHeritageClauses);
3345
3346            writeSpace();
3347            writePunctuation("{");
3348            emitList(node, node.members, ListFormat.ClassMembers);
3349            writePunctuation("}");
3350
3351            if (indentedFlag) {
3352                decreaseIndent();
3353            }
3354        }
3355
3356        function emitInterfaceDeclaration(node: InterfaceDeclaration) {
3357            emitModifiers(node, node.modifiers);
3358            writeKeyword("interface");
3359            writeSpace();
3360            emit(node.name);
3361            emitTypeParameters(node, node.typeParameters);
3362            emitList(node, node.heritageClauses, ListFormat.HeritageClauses);
3363            writeSpace();
3364            writePunctuation("{");
3365            emitList(node, node.members, ListFormat.InterfaceMembers);
3366            writePunctuation("}");
3367        }
3368
3369        function emitTypeAliasDeclaration(node: TypeAliasDeclaration) {
3370            emitModifiers(node, node.modifiers);
3371            writeKeyword("type");
3372            writeSpace();
3373            emit(node.name);
3374            emitTypeParameters(node, node.typeParameters);
3375            writeSpace();
3376            writePunctuation("=");
3377            writeSpace();
3378            emit(node.type);
3379            writeTrailingSemicolon();
3380        }
3381
3382        function emitEnumDeclaration(node: EnumDeclaration) {
3383            emitModifiers(node, node.modifiers);
3384            writeKeyword("enum");
3385            writeSpace();
3386            emit(node.name);
3387
3388            writeSpace();
3389            writePunctuation("{");
3390            emitList(node, node.members, ListFormat.EnumMembers);
3391            writePunctuation("}");
3392        }
3393
3394        function emitModuleDeclaration(node: ModuleDeclaration) {
3395            emitModifiers(node, node.modifiers);
3396            if (~node.flags & NodeFlags.GlobalAugmentation) {
3397                writeKeyword(node.flags & NodeFlags.Namespace ? "namespace" : "module");
3398                writeSpace();
3399            }
3400            emit(node.name);
3401
3402            let body = node.body;
3403            if (!body) return writeTrailingSemicolon();
3404            while (body && isModuleDeclaration(body)) {
3405                writePunctuation(".");
3406                emit(body.name);
3407                body = body.body;
3408            }
3409
3410            writeSpace();
3411            emit(body);
3412        }
3413
3414        function emitModuleBlock(node: ModuleBlock) {
3415            pushNameGenerationScope(node);
3416            forEach(node.statements, generateNames);
3417            emitBlockStatements(node, /*forceSingleLine*/ isEmptyBlock(node));
3418            popNameGenerationScope(node);
3419        }
3420
3421        function emitCaseBlock(node: CaseBlock) {
3422            emitTokenWithComment(SyntaxKind.OpenBraceToken, node.pos, writePunctuation, node);
3423            emitList(node, node.clauses, ListFormat.CaseBlockClauses);
3424            emitTokenWithComment(SyntaxKind.CloseBraceToken, node.clauses.end, writePunctuation, node, /*indentLeading*/ true);
3425        }
3426
3427        function emitImportEqualsDeclaration(node: ImportEqualsDeclaration) {
3428            emitModifiers(node, node.modifiers);
3429            emitTokenWithComment(SyntaxKind.ImportKeyword, node.modifiers ? node.modifiers.end : node.pos, writeKeyword, node);
3430            writeSpace();
3431            if (node.isTypeOnly) {
3432                emitTokenWithComment(SyntaxKind.TypeKeyword, node.pos, writeKeyword, node);
3433                writeSpace();
3434            }
3435            emit(node.name);
3436            writeSpace();
3437            emitTokenWithComment(SyntaxKind.EqualsToken, node.name.end, writePunctuation, node);
3438            writeSpace();
3439            emitModuleReference(node.moduleReference);
3440            writeTrailingSemicolon();
3441        }
3442
3443        function emitModuleReference(node: ModuleReference) {
3444            if (node.kind === SyntaxKind.Identifier) {
3445                emitExpression(node);
3446            }
3447            else {
3448                emit(node);
3449            }
3450        }
3451
3452        function emitImportDeclaration(node: ImportDeclaration) {
3453            emitModifiers(node, node.modifiers);
3454            emitTokenWithComment(SyntaxKind.ImportKeyword, node.modifiers ? node.modifiers.end : node.pos, writeKeyword, node);
3455            writeSpace();
3456            if (node.importClause) {
3457                emit(node.importClause);
3458                writeSpace();
3459                emitTokenWithComment(SyntaxKind.FromKeyword, node.importClause.end, writeKeyword, node);
3460                writeSpace();
3461            }
3462            emitExpression(node.moduleSpecifier);
3463            if (node.assertClause) {
3464                emitWithLeadingSpace(node.assertClause);
3465            }
3466            writeTrailingSemicolon();
3467        }
3468
3469        function emitImportClause(node: ImportClause) {
3470            if (node.isTypeOnly) {
3471                emitTokenWithComment(SyntaxKind.TypeKeyword, node.pos, writeKeyword, node);
3472                writeSpace();
3473            }
3474            emit(node.name);
3475            if (node.name && node.namedBindings) {
3476                emitTokenWithComment(SyntaxKind.CommaToken, node.name.end, writePunctuation, node);
3477                writeSpace();
3478            }
3479            emit(node.namedBindings);
3480        }
3481
3482        function emitNamespaceImport(node: NamespaceImport) {
3483            const asPos = emitTokenWithComment(SyntaxKind.AsteriskToken, node.pos, writePunctuation, node);
3484            writeSpace();
3485            emitTokenWithComment(SyntaxKind.AsKeyword, asPos, writeKeyword, node);
3486            writeSpace();
3487            emit(node.name);
3488        }
3489
3490        function emitNamedImports(node: NamedImports) {
3491            emitNamedImportsOrExports(node);
3492        }
3493
3494        function emitImportSpecifier(node: ImportSpecifier) {
3495            emitImportOrExportSpecifier(node);
3496        }
3497
3498        function emitExportAssignment(node: ExportAssignment) {
3499            const nextPos = emitTokenWithComment(SyntaxKind.ExportKeyword, node.pos, writeKeyword, node);
3500            writeSpace();
3501            if (node.isExportEquals) {
3502                emitTokenWithComment(SyntaxKind.EqualsToken, nextPos, writeOperator, node);
3503            }
3504            else {
3505                emitTokenWithComment(SyntaxKind.DefaultKeyword, nextPos, writeKeyword, node);
3506            }
3507            writeSpace();
3508            emitExpression(node.expression, node.isExportEquals ?
3509                parenthesizer.getParenthesizeRightSideOfBinaryForOperator(SyntaxKind.EqualsToken) :
3510                parenthesizer.parenthesizeExpressionOfExportDefault);
3511            writeTrailingSemicolon();
3512        }
3513
3514        function emitExportDeclaration(node: ExportDeclaration) {
3515            emitModifiers(node, node.modifiers);
3516            let nextPos = emitTokenWithComment(SyntaxKind.ExportKeyword, node.pos, writeKeyword, node);
3517            writeSpace();
3518            if (node.isTypeOnly) {
3519                nextPos = emitTokenWithComment(SyntaxKind.TypeKeyword, nextPos, writeKeyword, node);
3520                writeSpace();
3521            }
3522            if (node.exportClause) {
3523                emit(node.exportClause);
3524            }
3525            else {
3526                nextPos = emitTokenWithComment(SyntaxKind.AsteriskToken, nextPos, writePunctuation, node);
3527            }
3528            if (node.moduleSpecifier) {
3529                writeSpace();
3530                const fromPos = node.exportClause ? node.exportClause.end : nextPos;
3531                emitTokenWithComment(SyntaxKind.FromKeyword, fromPos, writeKeyword, node);
3532                writeSpace();
3533                emitExpression(node.moduleSpecifier);
3534            }
3535            if (node.assertClause) {
3536                emitWithLeadingSpace(node.assertClause);
3537            }
3538            writeTrailingSemicolon();
3539        }
3540
3541        function emitAssertClause(node: AssertClause) {
3542            emitTokenWithComment(SyntaxKind.AssertKeyword, node.pos, writeKeyword, node);
3543            writeSpace();
3544            const elements = node.elements;
3545            emitList(node, elements, ListFormat.ImportClauseEntries);
3546        }
3547
3548        function emitAssertEntry(node: AssertEntry) {
3549            emit(node.name);
3550            writePunctuation(":");
3551            writeSpace();
3552
3553            const value = node.value;
3554            /** @see {emitPropertyAssignment} */
3555            if ((getEmitFlags(value) & EmitFlags.NoLeadingComments) === 0) {
3556                const commentRange = getCommentRange(value);
3557                emitTrailingCommentsOfPosition(commentRange.pos);
3558            }
3559            emit(value);
3560        }
3561
3562        function emitNamespaceExportDeclaration(node: NamespaceExportDeclaration) {
3563            let nextPos = emitTokenWithComment(SyntaxKind.ExportKeyword, node.pos, writeKeyword, node);
3564            writeSpace();
3565            nextPos = emitTokenWithComment(SyntaxKind.AsKeyword, nextPos, writeKeyword, node);
3566            writeSpace();
3567            nextPos = emitTokenWithComment(SyntaxKind.NamespaceKeyword, nextPos, writeKeyword, node);
3568            writeSpace();
3569            emit(node.name);
3570            writeTrailingSemicolon();
3571        }
3572
3573        function emitNamespaceExport(node: NamespaceExport) {
3574            const asPos = emitTokenWithComment(SyntaxKind.AsteriskToken, node.pos, writePunctuation, node);
3575            writeSpace();
3576            emitTokenWithComment(SyntaxKind.AsKeyword, asPos, writeKeyword, node);
3577            writeSpace();
3578            emit(node.name);
3579        }
3580
3581        function emitNamedExports(node: NamedExports) {
3582            emitNamedImportsOrExports(node);
3583        }
3584
3585        function emitExportSpecifier(node: ExportSpecifier) {
3586            emitImportOrExportSpecifier(node);
3587        }
3588
3589        function emitNamedImportsOrExports(node: NamedImportsOrExports) {
3590            writePunctuation("{");
3591            emitList(node, node.elements, ListFormat.NamedImportsOrExportsElements);
3592            writePunctuation("}");
3593        }
3594
3595        function emitImportOrExportSpecifier(node: ImportOrExportSpecifier) {
3596            if (node.isTypeOnly) {
3597                writeKeyword("type");
3598                writeSpace();
3599            }
3600            if (node.propertyName) {
3601                emit(node.propertyName);
3602                writeSpace();
3603                emitTokenWithComment(SyntaxKind.AsKeyword, node.propertyName.end, writeKeyword, node);
3604                writeSpace();
3605            }
3606
3607            emit(node.name);
3608        }
3609
3610        //
3611        // Module references
3612        //
3613
3614        function emitExternalModuleReference(node: ExternalModuleReference) {
3615            writeKeyword("require");
3616            writePunctuation("(");
3617            emitExpression(node.expression);
3618            writePunctuation(")");
3619        }
3620
3621        //
3622        // JSX
3623        //
3624
3625        function emitJsxElement(node: JsxElement) {
3626            emit(node.openingElement);
3627            emitList(node, node.children, ListFormat.JsxElementOrFragmentChildren);
3628            emit(node.closingElement);
3629        }
3630
3631        function emitJsxSelfClosingElement(node: JsxSelfClosingElement) {
3632            writePunctuation("<");
3633            emitJsxTagName(node.tagName);
3634            emitTypeArguments(node, node.typeArguments);
3635            writeSpace();
3636            emit(node.attributes);
3637            writePunctuation("/>");
3638        }
3639
3640        function emitJsxFragment(node: JsxFragment) {
3641            emit(node.openingFragment);
3642            emitList(node, node.children, ListFormat.JsxElementOrFragmentChildren);
3643            emit(node.closingFragment);
3644        }
3645
3646        function emitJsxOpeningElementOrFragment(node: JsxOpeningElement | JsxOpeningFragment) {
3647            writePunctuation("<");
3648
3649            if (isJsxOpeningElement(node)) {
3650                const indented = writeLineSeparatorsAndIndentBefore(node.tagName, node);
3651                emitJsxTagName(node.tagName);
3652                emitTypeArguments(node, node.typeArguments);
3653                if (node.attributes.properties && node.attributes.properties.length > 0) {
3654                    writeSpace();
3655                }
3656                emit(node.attributes);
3657                writeLineSeparatorsAfter(node.attributes, node);
3658                decreaseIndentIf(indented);
3659            }
3660
3661            writePunctuation(">");
3662        }
3663
3664        function emitJsxText(node: JsxText) {
3665            writer.writeLiteral(node.text);
3666        }
3667
3668        function emitJsxClosingElementOrFragment(node: JsxClosingElement | JsxClosingFragment) {
3669            writePunctuation("</");
3670            if (isJsxClosingElement(node)) {
3671                emitJsxTagName(node.tagName);
3672            }
3673            writePunctuation(">");
3674        }
3675
3676        function emitJsxAttributes(node: JsxAttributes) {
3677            emitList(node, node.properties, ListFormat.JsxElementAttributes);
3678        }
3679
3680        function emitJsxAttribute(node: JsxAttribute) {
3681            emit(node.name);
3682            emitNodeWithPrefix("=", writePunctuation, node.initializer, emitJsxAttributeValue);
3683        }
3684
3685        function emitJsxSpreadAttribute(node: JsxSpreadAttribute) {
3686            writePunctuation("{...");
3687            emitExpression(node.expression);
3688            writePunctuation("}");
3689        }
3690
3691        function hasTrailingCommentsAtPosition(pos: number) {
3692            let result = false;
3693            forEachTrailingCommentRange(currentSourceFile?.text || "", pos + 1, () => result = true);
3694            return result;
3695        }
3696
3697        function hasLeadingCommentsAtPosition(pos: number) {
3698            let result = false;
3699            forEachLeadingCommentRange(currentSourceFile?.text || "", pos + 1, () => result = true);
3700            return result;
3701        }
3702
3703        function hasCommentsAtPosition(pos: number) {
3704            return hasTrailingCommentsAtPosition(pos) || hasLeadingCommentsAtPosition(pos);
3705        }
3706
3707        function emitJsxExpression(node: JsxExpression) {
3708            if (node.expression || (!commentsDisabled && !nodeIsSynthesized(node) && hasCommentsAtPosition(node.pos))) { // preserve empty expressions if they contain comments!
3709                const isMultiline = currentSourceFile && !nodeIsSynthesized(node) && getLineAndCharacterOfPosition(currentSourceFile, node.pos).line !== getLineAndCharacterOfPosition(currentSourceFile, node.end).line;
3710                if (isMultiline) {
3711                    writer.increaseIndent();
3712                }
3713                const end = emitTokenWithComment(SyntaxKind.OpenBraceToken, node.pos, writePunctuation, node);
3714                emit(node.dotDotDotToken);
3715                emitExpression(node.expression);
3716                emitTokenWithComment(SyntaxKind.CloseBraceToken, node.expression?.end || end, writePunctuation, node);
3717                if (isMultiline) {
3718                    writer.decreaseIndent();
3719                }
3720            }
3721        }
3722
3723        function emitJsxTagName(node: JsxTagNameExpression) {
3724            if (node.kind === SyntaxKind.Identifier) {
3725                emitExpression(node);
3726            }
3727            else {
3728                emit(node);
3729            }
3730        }
3731
3732        //
3733        // Clauses
3734        //
3735
3736        function emitCaseClause(node: CaseClause) {
3737            emitTokenWithComment(SyntaxKind.CaseKeyword, node.pos, writeKeyword, node);
3738            writeSpace();
3739            emitExpression(node.expression, parenthesizer.parenthesizeExpressionForDisallowedComma);
3740
3741            emitCaseOrDefaultClauseRest(node, node.statements, node.expression.end);
3742        }
3743
3744        function emitDefaultClause(node: DefaultClause) {
3745            const pos = emitTokenWithComment(SyntaxKind.DefaultKeyword, node.pos, writeKeyword, node);
3746            emitCaseOrDefaultClauseRest(node, node.statements, pos);
3747        }
3748
3749        function emitCaseOrDefaultClauseRest(parentNode: Node, statements: NodeArray<Statement>, colonPos: number) {
3750            const emitAsSingleStatement =
3751                statements.length === 1 &&
3752                (
3753                    // treat synthesized nodes as located on the same line for emit purposes
3754                    !currentSourceFile ||
3755                    nodeIsSynthesized(parentNode) ||
3756                    nodeIsSynthesized(statements[0]) ||
3757                    rangeStartPositionsAreOnSameLine(parentNode, statements[0], currentSourceFile)
3758                );
3759
3760            let format = ListFormat.CaseOrDefaultClauseStatements;
3761            if (emitAsSingleStatement) {
3762                writeToken(SyntaxKind.ColonToken, colonPos, writePunctuation, parentNode);
3763                writeSpace();
3764                format &= ~(ListFormat.MultiLine | ListFormat.Indented);
3765            }
3766            else {
3767                emitTokenWithComment(SyntaxKind.ColonToken, colonPos, writePunctuation, parentNode);
3768            }
3769            emitList(parentNode, statements, format);
3770        }
3771
3772        function emitHeritageClause(node: HeritageClause) {
3773            writeSpace();
3774            writeTokenText(node.token, writeKeyword);
3775            writeSpace();
3776            emitList(node, node.types, ListFormat.HeritageClauseTypes);
3777        }
3778
3779        function emitCatchClause(node: CatchClause) {
3780            const openParenPos = emitTokenWithComment(SyntaxKind.CatchKeyword, node.pos, writeKeyword, node);
3781            writeSpace();
3782            if (node.variableDeclaration) {
3783                emitTokenWithComment(SyntaxKind.OpenParenToken, openParenPos, writePunctuation, node);
3784                emit(node.variableDeclaration);
3785                emitTokenWithComment(SyntaxKind.CloseParenToken, node.variableDeclaration.end, writePunctuation, node);
3786                writeSpace();
3787            }
3788            emit(node.block);
3789        }
3790
3791        //
3792        // Property assignments
3793        //
3794
3795        function emitPropertyAssignment(node: PropertyAssignment) {
3796            emit(node.name);
3797            writePunctuation(":");
3798            writeSpace();
3799            // This is to ensure that we emit comment in the following case:
3800            //      For example:
3801            //          obj = {
3802            //              id: /*comment1*/ ()=>void
3803            //          }
3804            // "comment1" is not considered to be leading comment for node.initializer
3805            // but rather a trailing comment on the previous node.
3806            const initializer = node.initializer;
3807            if ((getEmitFlags(initializer) & EmitFlags.NoLeadingComments) === 0) {
3808                const commentRange = getCommentRange(initializer);
3809                emitTrailingCommentsOfPosition(commentRange.pos);
3810            }
3811            emitExpression(initializer, parenthesizer.parenthesizeExpressionForDisallowedComma);
3812        }
3813
3814        function emitShorthandPropertyAssignment(node: ShorthandPropertyAssignment) {
3815            emit(node.name);
3816            if (node.objectAssignmentInitializer) {
3817                writeSpace();
3818                writePunctuation("=");
3819                writeSpace();
3820                emitExpression(node.objectAssignmentInitializer, parenthesizer.parenthesizeExpressionForDisallowedComma);
3821            }
3822        }
3823
3824        function emitSpreadAssignment(node: SpreadAssignment) {
3825            if (node.expression) {
3826                emitTokenWithComment(SyntaxKind.DotDotDotToken, node.pos, writePunctuation, node);
3827                emitExpression(node.expression, parenthesizer.parenthesizeExpressionForDisallowedComma);
3828            }
3829        }
3830
3831        //
3832        // Enum
3833        //
3834
3835        function emitEnumMember(node: EnumMember) {
3836            emit(node.name);
3837            emitInitializer(node.initializer, node.name.end, node, parenthesizer.parenthesizeExpressionForDisallowedComma);
3838        }
3839
3840        //
3841        // JSDoc
3842        //
3843        function emitJSDoc(node: JSDoc) {
3844            write("/**");
3845            if (node.comment) {
3846                const text = getTextOfJSDocComment(node.comment);
3847                if (text) {
3848                    const lines = text.split(/\r\n?|\n/g);
3849                    for (const line of lines) {
3850                        writeLine();
3851                        writeSpace();
3852                        writePunctuation("*");
3853                        writeSpace();
3854                        write(line);
3855                    }
3856                }
3857            }
3858            if (node.tags) {
3859                if (node.tags.length === 1 && node.tags[0].kind === SyntaxKind.JSDocTypeTag && !node.comment) {
3860                    writeSpace();
3861                    emit(node.tags[0]);
3862                }
3863                else {
3864                    emitList(node, node.tags, ListFormat.JSDocComment);
3865                }
3866            }
3867            writeSpace();
3868            write("*/");
3869        }
3870
3871        function emitJSDocSimpleTypedTag(tag: JSDocTypeTag | JSDocThisTag | JSDocEnumTag | JSDocReturnTag) {
3872            emitJSDocTagName(tag.tagName);
3873            emitJSDocTypeExpression(tag.typeExpression);
3874            emitJSDocComment(tag.comment);
3875        }
3876
3877        function emitJSDocSeeTag(tag: JSDocSeeTag) {
3878            emitJSDocTagName(tag.tagName);
3879            emit(tag.name);
3880            emitJSDocComment(tag.comment);
3881        }
3882
3883        function emitJSDocNameReference(node: JSDocNameReference) {
3884            writeSpace();
3885            writePunctuation("{");
3886            emit(node.name);
3887            writePunctuation("}");
3888        }
3889
3890        function emitJSDocHeritageTag(tag: JSDocImplementsTag | JSDocAugmentsTag) {
3891            emitJSDocTagName(tag.tagName);
3892            writeSpace();
3893            writePunctuation("{");
3894            emit(tag.class);
3895            writePunctuation("}");
3896            emitJSDocComment(tag.comment);
3897        }
3898
3899        function emitJSDocTemplateTag(tag: JSDocTemplateTag) {
3900            emitJSDocTagName(tag.tagName);
3901            emitJSDocTypeExpression(tag.constraint);
3902            writeSpace();
3903            emitList(tag, tag.typeParameters, ListFormat.CommaListElements);
3904            emitJSDocComment(tag.comment);
3905        }
3906
3907        function emitJSDocTypedefTag(tag: JSDocTypedefTag) {
3908            emitJSDocTagName(tag.tagName);
3909            if (tag.typeExpression) {
3910                if (tag.typeExpression.kind === SyntaxKind.JSDocTypeExpression) {
3911                    emitJSDocTypeExpression(tag.typeExpression);
3912                }
3913                else {
3914                    writeSpace();
3915                    writePunctuation("{");
3916                    write("Object");
3917                    if (tag.typeExpression.isArrayType) {
3918                        writePunctuation("[");
3919                        writePunctuation("]");
3920                    }
3921                    writePunctuation("}");
3922                }
3923            }
3924            if (tag.fullName) {
3925                writeSpace();
3926                emit(tag.fullName);
3927            }
3928            emitJSDocComment(tag.comment);
3929            if (tag.typeExpression && tag.typeExpression.kind === SyntaxKind.JSDocTypeLiteral) {
3930                emitJSDocTypeLiteral(tag.typeExpression);
3931            }
3932        }
3933
3934        function emitJSDocCallbackTag(tag: JSDocCallbackTag) {
3935            emitJSDocTagName(tag.tagName);
3936            if (tag.name) {
3937                writeSpace();
3938                emit(tag.name);
3939            }
3940            emitJSDocComment(tag.comment);
3941            emitJSDocSignature(tag.typeExpression);
3942        }
3943
3944        function emitJSDocSimpleTag(tag: JSDocTag) {
3945            emitJSDocTagName(tag.tagName);
3946            emitJSDocComment(tag.comment);
3947        }
3948
3949        function emitJSDocTypeLiteral(lit: JSDocTypeLiteral) {
3950            emitList(lit, factory.createNodeArray(lit.jsDocPropertyTags), ListFormat.JSDocComment);
3951        }
3952
3953        function emitJSDocSignature(sig: JSDocSignature) {
3954            if (sig.typeParameters) {
3955                emitList(sig, factory.createNodeArray(sig.typeParameters), ListFormat.JSDocComment);
3956            }
3957            if (sig.parameters) {
3958                emitList(sig, factory.createNodeArray(sig.parameters), ListFormat.JSDocComment);
3959            }
3960            if (sig.type) {
3961                writeLine();
3962                writeSpace();
3963                writePunctuation("*");
3964                writeSpace();
3965                emit(sig.type);
3966            }
3967        }
3968
3969        function emitJSDocPropertyLikeTag(param: JSDocPropertyLikeTag) {
3970            emitJSDocTagName(param.tagName);
3971            emitJSDocTypeExpression(param.typeExpression);
3972            writeSpace();
3973            if (param.isBracketed) {
3974                writePunctuation("[");
3975            }
3976            emit(param.name);
3977            if (param.isBracketed) {
3978                writePunctuation("]");
3979            }
3980            emitJSDocComment(param.comment);
3981        }
3982
3983        function emitJSDocTagName(tagName: Identifier) {
3984            writePunctuation("@");
3985            emit(tagName);
3986        }
3987
3988        function emitJSDocComment(comment: string | NodeArray<JSDocComment> | undefined) {
3989            const text = getTextOfJSDocComment(comment);
3990            if (text) {
3991                writeSpace();
3992                write(text);
3993            }
3994        }
3995
3996        function emitJSDocTypeExpression(typeExpression: JSDocTypeExpression | undefined) {
3997            if (typeExpression) {
3998                writeSpace();
3999                writePunctuation("{");
4000                emit(typeExpression.type);
4001                writePunctuation("}");
4002            }
4003        }
4004
4005        //
4006        // Top-level nodes
4007        //
4008
4009        function emitSourceFile(node: SourceFile) {
4010            writeLine();
4011            const statements = node.statements;
4012            // Emit detached comment if there are no prologue directives or if the first node is synthesized.
4013            // The synthesized node will have no leading comment so some comments may be missed.
4014            const shouldEmitDetachedComment = statements.length === 0 ||
4015                !isPrologueDirective(statements[0]) ||
4016                nodeIsSynthesized(statements[0]);
4017            if (shouldEmitDetachedComment) {
4018                emitBodyWithDetachedComments(node, statements, emitSourceFileWorker);
4019                return;
4020            }
4021            emitSourceFileWorker(node);
4022        }
4023
4024        function emitSyntheticTripleSlashReferencesIfNeeded(node: Bundle) {
4025            emitTripleSlashDirectives(!!node.hasNoDefaultLib, node.syntheticFileReferences || [], node.syntheticTypeReferences || [], node.syntheticLibReferences || []);
4026            for (const prepend of node.prepends) {
4027                if (isUnparsedSource(prepend) && prepend.syntheticReferences) {
4028                    for (const ref of prepend.syntheticReferences) {
4029                        emit(ref);
4030                        writeLine();
4031                    }
4032                }
4033            }
4034        }
4035
4036        function emitTripleSlashDirectivesIfNeeded(node: SourceFile) {
4037            if (node.isDeclarationFile) emitTripleSlashDirectives(node.hasNoDefaultLib, node.referencedFiles, node.typeReferenceDirectives, node.libReferenceDirectives);
4038        }
4039
4040        function emitTripleSlashDirectives(hasNoDefaultLib: boolean, files: readonly FileReference[], types: readonly FileReference[], libs: readonly FileReference[]) {
4041            if (hasNoDefaultLib) {
4042                const pos = writer.getTextPos();
4043                writeComment(`/// <reference no-default-lib="true"/>`);
4044                if (bundleFileInfo) bundleFileInfo.sections.push({ pos, end: writer.getTextPos(), kind: BundleFileSectionKind.NoDefaultLib });
4045                writeLine();
4046            }
4047            if (currentSourceFile && currentSourceFile.moduleName) {
4048                writeComment(`/// <amd-module name="${currentSourceFile.moduleName}" />`);
4049                writeLine();
4050            }
4051            if (currentSourceFile && currentSourceFile.amdDependencies) {
4052                for (const dep of currentSourceFile.amdDependencies) {
4053                    if (dep.name) {
4054                        writeComment(`/// <amd-dependency name="${dep.name}" path="${dep.path}" />`);
4055                    }
4056                    else {
4057                        writeComment(`/// <amd-dependency path="${dep.path}" />`);
4058                    }
4059                    writeLine();
4060                }
4061            }
4062            for (const directive of files) {
4063                const pos = writer.getTextPos();
4064                writeComment(`/// <reference path="${directive.fileName}" />`);
4065                if (bundleFileInfo) bundleFileInfo.sections.push({ pos, end: writer.getTextPos(), kind: BundleFileSectionKind.Reference, data: directive.fileName });
4066                writeLine();
4067            }
4068            for (const directive of types) {
4069                const pos = writer.getTextPos();
4070                const resolutionMode = directive.resolutionMode && directive.resolutionMode !== currentSourceFile?.impliedNodeFormat
4071                    ? `resolution-mode="${directive.resolutionMode === ModuleKind.ESNext ? "import" : "require"}"`
4072                    : "";
4073                writeComment(`/// <reference types="${directive.fileName}" ${resolutionMode}/>`);
4074                if (bundleFileInfo) bundleFileInfo.sections.push({ pos, end: writer.getTextPos(), kind: !directive.resolutionMode ? BundleFileSectionKind.Type : directive.resolutionMode === ModuleKind.ESNext ? BundleFileSectionKind.TypeResolutionModeImport : BundleFileSectionKind.TypeResolutionModeRequire, data: directive.fileName });
4075                writeLine();
4076            }
4077            for (const directive of libs) {
4078                const pos = writer.getTextPos();
4079                writeComment(`/// <reference lib="${directive.fileName}" />`);
4080                if (bundleFileInfo) bundleFileInfo.sections.push({ pos, end: writer.getTextPos(), kind: BundleFileSectionKind.Lib, data: directive.fileName });
4081                writeLine();
4082            }
4083        }
4084
4085        function emitSourceFileWorker(node: SourceFile) {
4086            const statements = node.statements;
4087            pushNameGenerationScope(node);
4088            forEach(node.statements, generateNames);
4089            emitHelpers(node);
4090            const index = findIndex(statements, statement => !isPrologueDirective(statement));
4091            emitTripleSlashDirectivesIfNeeded(node);
4092            emitList(node, statements, ListFormat.MultiLine, /*parenthesizerRule*/ undefined, index === -1 ? statements.length : index);
4093            popNameGenerationScope(node);
4094        }
4095
4096        // Transformation nodes
4097
4098        function emitPartiallyEmittedExpression(node: PartiallyEmittedExpression) {
4099            const emitFlags = getEmitFlags(node);
4100            if (!(emitFlags & EmitFlags.NoLeadingComments) && node.pos !== node.expression.pos) {
4101                emitTrailingCommentsOfPosition(node.expression.pos);
4102            }
4103            emitExpression(node.expression);
4104            if (!(emitFlags & EmitFlags.NoTrailingComments) && node.end !== node.expression.end) {
4105                emitLeadingCommentsOfPosition(node.expression.end);
4106            }
4107        }
4108
4109        function emitCommaList(node: CommaListExpression) {
4110            emitExpressionList(node, node.elements, ListFormat.CommaListElements, /*parenthesizerRule*/ undefined);
4111        }
4112
4113        /**
4114         * Emits any prologue directives at the start of a Statement list, returning the
4115         * number of prologue directives written to the output.
4116         */
4117        function emitPrologueDirectives(statements: readonly Node[], sourceFile?: SourceFile, seenPrologueDirectives?: Set<string>, recordBundleFileSection?: true): number {
4118            let needsToSetSourceFile = !!sourceFile;
4119            for (let i = 0; i < statements.length; i++) {
4120                const statement = statements[i];
4121                if (isPrologueDirective(statement)) {
4122                    const shouldEmitPrologueDirective = seenPrologueDirectives ? !seenPrologueDirectives.has(statement.expression.text) : true;
4123                    if (shouldEmitPrologueDirective) {
4124                        if (needsToSetSourceFile) {
4125                            needsToSetSourceFile = false;
4126                            setSourceFile(sourceFile);
4127                        }
4128                        writeLine();
4129                        const pos = writer.getTextPos();
4130                        emit(statement);
4131                        if (recordBundleFileSection && bundleFileInfo) bundleFileInfo.sections.push({ pos, end: writer.getTextPos(), kind: BundleFileSectionKind.Prologue, data: statement.expression.text });
4132                        if (seenPrologueDirectives) {
4133                            seenPrologueDirectives.add(statement.expression.text);
4134                        }
4135                    }
4136                }
4137                else {
4138                    // return index of the first non prologue directive
4139                    return i;
4140                }
4141            }
4142
4143            return statements.length;
4144        }
4145
4146        function emitUnparsedPrologues(prologues: readonly UnparsedPrologue[], seenPrologueDirectives: Set<string>) {
4147            for (const prologue of prologues) {
4148                if (!seenPrologueDirectives.has(prologue.data)) {
4149                    writeLine();
4150                    const pos = writer.getTextPos();
4151                    emit(prologue);
4152                    if (bundleFileInfo) bundleFileInfo.sections.push({ pos, end: writer.getTextPos(), kind: BundleFileSectionKind.Prologue, data: prologue.data });
4153                    if (seenPrologueDirectives) {
4154                        seenPrologueDirectives.add(prologue.data);
4155                    }
4156                }
4157            }
4158        }
4159
4160        function emitPrologueDirectivesIfNeeded(sourceFileOrBundle: Bundle | SourceFile) {
4161            if (isSourceFile(sourceFileOrBundle)) {
4162                emitPrologueDirectives(sourceFileOrBundle.statements, sourceFileOrBundle);
4163            }
4164            else {
4165                const seenPrologueDirectives = new Set<string>();
4166                for (const prepend of sourceFileOrBundle.prepends) {
4167                    emitUnparsedPrologues((prepend as UnparsedSource).prologues, seenPrologueDirectives);
4168                }
4169                for (const sourceFile of sourceFileOrBundle.sourceFiles) {
4170                    emitPrologueDirectives(sourceFile.statements, sourceFile, seenPrologueDirectives, /*recordBundleFileSection*/ true);
4171                }
4172                setSourceFile(undefined);
4173            }
4174        }
4175
4176        function getPrologueDirectivesFromBundledSourceFiles(bundle: Bundle): SourceFilePrologueInfo[] | undefined {
4177            const seenPrologueDirectives = new Set<string>();
4178            let prologues: SourceFilePrologueInfo[] | undefined;
4179            for (let index = 0; index < bundle.sourceFiles.length; index++) {
4180                const sourceFile = bundle.sourceFiles[index];
4181                let directives: SourceFilePrologueDirective[] | undefined;
4182                let end = 0;
4183                for (const statement of sourceFile.statements) {
4184                    if (!isPrologueDirective(statement)) break;
4185                    if (seenPrologueDirectives.has(statement.expression.text)) continue;
4186                    seenPrologueDirectives.add(statement.expression.text);
4187                    (directives || (directives = [])).push({
4188                        pos: statement.pos,
4189                        end: statement.end,
4190                        expression: {
4191                            pos: statement.expression.pos,
4192                            end: statement.expression.end,
4193                            text: statement.expression.text
4194                        }
4195                    });
4196                    end = end < statement.end ? statement.end : end;
4197                }
4198                if (directives) (prologues || (prologues = [])).push({ file: index, text: sourceFile.text.substring(0, end), directives });
4199            }
4200            return prologues;
4201        }
4202
4203        function emitShebangIfNeeded(sourceFileOrBundle: Bundle | SourceFile | UnparsedSource) {
4204            if (isSourceFile(sourceFileOrBundle) || isUnparsedSource(sourceFileOrBundle)) {
4205                const shebang = getShebang(sourceFileOrBundle.text);
4206                if (shebang) {
4207                    writeComment(shebang);
4208                    writeLine();
4209                    return true;
4210                }
4211            }
4212            else {
4213                for (const prepend of sourceFileOrBundle.prepends) {
4214                    Debug.assertNode(prepend, isUnparsedSource);
4215                    if (emitShebangIfNeeded(prepend)) {
4216                        return true;
4217                    }
4218                }
4219                for (const sourceFile of sourceFileOrBundle.sourceFiles) {
4220                    // Emit only the first encountered shebang
4221                    if (emitShebangIfNeeded(sourceFile)) {
4222                        return true;
4223                    }
4224                }
4225            }
4226        }
4227
4228        //
4229        // Helpers
4230        //
4231
4232        function emitNodeWithWriter(node: Node | undefined, writer: typeof write) {
4233            if (!node) return;
4234            const savedWrite = write;
4235            write = writer;
4236            emit(node);
4237            write = savedWrite;
4238        }
4239
4240        function emitDecoratorsAndModifiers(node: Node, modifiers: NodeArray<ModifierLike> | undefined) {
4241            if (modifiers?.length) {
4242                if (every(modifiers, isModifier)) {
4243                    // if all modifier-likes are `Modifier`, simply emit the array as modifiers.
4244                    return emitModifiers(node, modifiers as NodeArray<Modifier>);
4245                }
4246
4247                if (every(modifiers, isDecorator)) {
4248                    // if all modifier-likes are `Decorator`, simply emit the array as decorators.
4249                    return emitDecorators(node, modifiers as NodeArray<Decorator>);
4250                }
4251
4252                onBeforeEmitNodeArray?.(modifiers);
4253
4254                // partition modifiers into contiguous chunks of `Modifier` or `Decorator`
4255                let lastMode: "modifiers" | "decorators" | undefined;
4256                let mode: "modifiers" | "decorators" | undefined;
4257                let start = 0;
4258                let pos = 0;
4259                while (start < modifiers.length) {
4260                    while (pos < modifiers.length) {
4261                        const modifier = modifiers[pos];
4262                        mode = isDecorator(modifier) ? "decorators" : "modifiers";
4263                        if (lastMode === undefined) {
4264                            lastMode = mode;
4265                        }
4266                        else if (mode !== lastMode) {
4267                            break;
4268                        }
4269
4270                        pos++;
4271                    }
4272
4273                    const textRange: TextRange = { pos: -1, end: -1 };
4274                    if (start === 0) textRange.pos = modifiers.pos;
4275                    if (pos === modifiers.length - 1) textRange.end = modifiers.end;
4276                    emitNodeListItems(
4277                        emit,
4278                        node,
4279                        modifiers,
4280                        lastMode === "modifiers" ? ListFormat.Modifiers : ListFormat.Decorators,
4281                        /*parenthesizerRule*/ undefined,
4282                        start,
4283                        pos - start,
4284                        /*hasTrailingComma*/ false,
4285                        textRange);
4286                    start = pos;
4287                    lastMode = mode;
4288                    pos++;
4289                }
4290
4291                onAfterEmitNodeArray?.(modifiers);
4292            }
4293        }
4294
4295        function emitModifiers(node: Node, modifiers: NodeArray<Modifier> | undefined): void {
4296            emitList(node, modifiers, ListFormat.Modifiers);
4297        }
4298
4299        function emitTypeAnnotation(node: TypeNode | undefined) {
4300            if (node) {
4301                writePunctuation(":");
4302                writeSpace();
4303                emit(node);
4304            }
4305        }
4306
4307        function emitInitializer(node: Expression | undefined, equalCommentStartPos: number, container: Node, parenthesizerRule?: (node: Expression) => Expression) {
4308            if (node) {
4309                writeSpace();
4310                emitTokenWithComment(SyntaxKind.EqualsToken, equalCommentStartPos, writeOperator, container);
4311                writeSpace();
4312                emitExpression(node, parenthesizerRule);
4313            }
4314        }
4315
4316        function emitNodeWithPrefix<T extends Node>(prefix: string, prefixWriter: (s: string) => void, node: T | undefined, emit: (node: T) => void) {
4317            if (node) {
4318                prefixWriter(prefix);
4319                emit(node);
4320            }
4321        }
4322
4323        function emitWithLeadingSpace(node: Node | undefined) {
4324            if (node) {
4325                writeSpace();
4326                emit(node);
4327            }
4328        }
4329
4330        function emitExpressionWithLeadingSpace(node: Expression | undefined, parenthesizerRule?: (node: Expression) => Expression) {
4331            if (node) {
4332                writeSpace();
4333                emitExpression(node, parenthesizerRule);
4334            }
4335        }
4336
4337        function emitWithTrailingSpace(node: Node | undefined) {
4338            if (node) {
4339                emit(node);
4340                writeSpace();
4341            }
4342        }
4343
4344        function emitEmbeddedStatement(parent: Node, node: Statement) {
4345            if (isBlock(node) || getEmitFlags(parent) & EmitFlags.SingleLine) {
4346                writeSpace();
4347                emit(node);
4348            }
4349            else {
4350                writeLine();
4351                increaseIndent();
4352                if (isEmptyStatement(node)) {
4353                    pipelineEmit(EmitHint.EmbeddedStatement, node);
4354                }
4355                else {
4356                    emit(node);
4357                }
4358                decreaseIndent();
4359            }
4360        }
4361
4362        function emitDecorators(parentNode: Node, decorators: NodeArray<Decorator> | undefined): void {
4363            emitList(parentNode, decorators, ListFormat.Decorators);
4364        }
4365
4366        function emitTypeArguments(parentNode: Node, typeArguments: NodeArray<TypeNode> | undefined) {
4367            emitList(parentNode, typeArguments, ListFormat.TypeArguments, typeArgumentParenthesizerRuleSelector);
4368        }
4369
4370        function emitTypeParameters(parentNode: SignatureDeclaration | InterfaceDeclaration | TypeAliasDeclaration | ClassDeclaration | ClassExpression | StructDeclaration, typeParameters: NodeArray<TypeParameterDeclaration> | undefined) {
4371            if (isFunctionLike(parentNode) && parentNode.typeArguments) { // Quick info uses type arguments in place of type parameters on instantiated signatures
4372                return emitTypeArguments(parentNode, parentNode.typeArguments);
4373            }
4374            emitList(parentNode, typeParameters, ListFormat.TypeParameters);
4375        }
4376
4377        function emitParameters(parentNode: Node, parameters: NodeArray<ParameterDeclaration>) {
4378            emitList(parentNode, parameters, ListFormat.Parameters);
4379        }
4380
4381        function canEmitSimpleArrowHead(parentNode: FunctionTypeNode | ArrowFunction, parameters: NodeArray<ParameterDeclaration>) {
4382            const parameter = singleOrUndefined(parameters);
4383            return parameter
4384                && parameter.pos === parentNode.pos // may not have parsed tokens between parent and parameter
4385                && isArrowFunction(parentNode)      // only arrow functions may have simple arrow head
4386                && !parentNode.type                 // arrow function may not have return type annotation
4387                && !some(parentNode.modifiers)      // parent may not have decorators or modifiers
4388                && !some(parentNode.typeParameters) // parent may not have type parameters
4389                && !some(parameter.modifiers)       // parameter may not have decorators or modifiers
4390                && !parameter.dotDotDotToken        // parameter may not be rest
4391                && !parameter.questionToken         // parameter may not be optional
4392                && !parameter.type                  // parameter may not have a type annotation
4393                && !parameter.initializer           // parameter may not have an initializer
4394                && isIdentifier(parameter.name);    // parameter name must be identifier
4395        }
4396
4397        function emitParametersForArrow(parentNode: FunctionTypeNode | ArrowFunction, parameters: NodeArray<ParameterDeclaration>) {
4398            if (canEmitSimpleArrowHead(parentNode, parameters)) {
4399                emitList(parentNode, parameters, ListFormat.Parameters & ~ListFormat.Parenthesis);
4400            }
4401            else {
4402                emitParameters(parentNode, parameters);
4403            }
4404        }
4405
4406        function emitParametersForIndexSignature(parentNode: Node, parameters: NodeArray<ParameterDeclaration>) {
4407            emitList(parentNode, parameters, ListFormat.IndexSignatureParameters);
4408        }
4409
4410        function writeDelimiter(format: ListFormat) {
4411            switch (format & ListFormat.DelimitersMask) {
4412                case ListFormat.None:
4413                    break;
4414                case ListFormat.CommaDelimited:
4415                    writePunctuation(",");
4416                    break;
4417                case ListFormat.BarDelimited:
4418                    writeSpace();
4419                    writePunctuation("|");
4420                    break;
4421                case ListFormat.AsteriskDelimited:
4422                    writeSpace();
4423                    writePunctuation("*");
4424                    writeSpace();
4425                    break;
4426                case ListFormat.AmpersandDelimited:
4427                    writeSpace();
4428                    writePunctuation("&");
4429                    break;
4430            }
4431        }
4432
4433        function emitList(parentNode: Node | undefined, children: NodeArray<Node> | undefined, format: ListFormat, parenthesizerRule?: ParenthesizerRuleOrSelector<Node>, start?: number, count?: number) {
4434            emitNodeList(emit, parentNode, children, format, parenthesizerRule, start, count);
4435        }
4436
4437        function emitExpressionList(parentNode: Node | undefined, children: NodeArray<Node> | undefined, format: ListFormat, parenthesizerRule?: ParenthesizerRuleOrSelector<Expression>, start?: number, count?: number) {
4438            emitNodeList(emitExpression, parentNode, children, format, parenthesizerRule, start, count);
4439        }
4440
4441        function emitNodeList(emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parentNode: Node | undefined, children: NodeArray<Node> | undefined, format: ListFormat, parenthesizerRule: ParenthesizerRuleOrSelector<Node> | undefined, start = 0, count = children ? children.length - start : 0) {
4442            const isUndefined = children === undefined;
4443            if (isUndefined && format & ListFormat.OptionalIfUndefined) {
4444                return;
4445            }
4446
4447            const isEmpty = children === undefined || start >= children.length || count === 0;
4448            if (isEmpty && format & ListFormat.OptionalIfEmpty) {
4449                onBeforeEmitNodeArray?.(children);
4450                onAfterEmitNodeArray?.(children);
4451                return;
4452            }
4453
4454            if (format & ListFormat.BracketsMask) {
4455                writePunctuation(getOpeningBracket(format));
4456                if (isEmpty && children) {
4457                    emitTrailingCommentsOfPosition(children.pos, /*prefixSpace*/ true); // Emit comments within empty bracketed lists
4458                }
4459            }
4460
4461            onBeforeEmitNodeArray?.(children);
4462
4463            if (isEmpty) {
4464                // Write a line terminator if the parent node was multi-line
4465                if (format & ListFormat.MultiLine && !(preserveSourceNewlines && (!parentNode || currentSourceFile && rangeIsOnSingleLine(parentNode, currentSourceFile)))) {
4466                    writeLine();
4467                }
4468                else if (format & ListFormat.SpaceBetweenBraces && !(format & ListFormat.NoSpaceIfEmpty)) {
4469                    writeSpace();
4470                }
4471            }
4472            else {
4473                emitNodeListItems(emit, parentNode, children, format, parenthesizerRule, start, count, children.hasTrailingComma, children);
4474            }
4475
4476            onAfterEmitNodeArray?.(children);
4477
4478            if (format & ListFormat.BracketsMask) {
4479                if (isEmpty && children) {
4480                    emitLeadingCommentsOfPosition(children.end); // Emit leading comments within empty lists
4481                }
4482                writePunctuation(getClosingBracket(format));
4483            }
4484        }
4485
4486        /**
4487         * Emits a list without brackets or raising events.
4488         *
4489         * NOTE: You probably don't want to call this directly and should be using `emitList` or `emitExpressionList` instead.
4490         */
4491        function emitNodeListItems(emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parentNode: Node | undefined, children: readonly Node[], format: ListFormat, parenthesizerRule: ParenthesizerRuleOrSelector<Node> | undefined, start: number, count: number, hasTrailingComma: boolean, childrenTextRange: TextRange | undefined) {
4492            // Write the opening line terminator or leading whitespace.
4493            const mayEmitInterveningComments = (format & ListFormat.NoInterveningComments) === 0;
4494            let shouldEmitInterveningComments = mayEmitInterveningComments;
4495
4496            const leadingLineTerminatorCount = getLeadingLineTerminatorCount(parentNode, children[start], format);
4497            if (leadingLineTerminatorCount) {
4498                writeLine(leadingLineTerminatorCount);
4499                shouldEmitInterveningComments = false;
4500            }
4501            else if (format & ListFormat.SpaceBetweenBraces) {
4502                writeSpace();
4503            }
4504
4505            // Increase the indent, if requested.
4506            if (format & ListFormat.Indented) {
4507                increaseIndent();
4508            }
4509
4510            const emitListItem = getEmitListItem(emit, parenthesizerRule);
4511
4512            // Emit each child.
4513            let previousSibling: Node | undefined;
4514            let previousSourceFileTextKind: ReturnType<typeof recordBundleFileInternalSectionStart>;
4515            let shouldDecreaseIndentAfterEmit = false;
4516            for (let i = 0; i < count; i++) {
4517                const child = children[start + i];
4518
4519                // Write the delimiter if this is not the first node.
4520                if (format & ListFormat.AsteriskDelimited) {
4521                    // always write JSDoc in the format "\n *"
4522                    writeLine();
4523                    writeDelimiter(format);
4524                }
4525                else if (previousSibling) {
4526                    // i.e
4527                    //      function commentedParameters(
4528                    //          /* Parameter a */
4529                    //          a
4530                    //          /* End of parameter a */ -> this comment isn't considered to be trailing comment of parameter "a" due to newline
4531                    //          ,
4532                    if (format & ListFormat.DelimitersMask && previousSibling.end !== (parentNode ? parentNode.end : -1)) {
4533                        emitLeadingCommentsOfPosition(previousSibling.end);
4534                    }
4535                    writeDelimiter(format);
4536                    recordBundleFileInternalSectionEnd(previousSourceFileTextKind);
4537
4538                    // Write either a line terminator or whitespace to separate the elements.
4539                    const separatingLineTerminatorCount = getSeparatingLineTerminatorCount(previousSibling, child, format);
4540                    if (separatingLineTerminatorCount > 0) {
4541                        // If a synthesized node in a single-line list starts on a new
4542                        // line, we should increase the indent.
4543                        if ((format & (ListFormat.LinesMask | ListFormat.Indented)) === ListFormat.SingleLine) {
4544                            increaseIndent();
4545                            shouldDecreaseIndentAfterEmit = true;
4546                        }
4547
4548                        writeLine(separatingLineTerminatorCount);
4549                        shouldEmitInterveningComments = false;
4550                    }
4551                    else if (previousSibling && format & ListFormat.SpaceBetweenSiblings) {
4552                        writeSpace();
4553                    }
4554                }
4555
4556                // Emit this child.
4557                previousSourceFileTextKind = recordBundleFileInternalSectionStart(child);
4558                if (shouldEmitInterveningComments) {
4559                    const commentRange = getCommentRange(child);
4560                    emitTrailingCommentsOfPosition(commentRange.pos);
4561                }
4562                else {
4563                    shouldEmitInterveningComments = mayEmitInterveningComments;
4564                }
4565
4566                nextListElementPos = child.pos;
4567                emitListItem(child, emit, parenthesizerRule, i);
4568
4569                if (shouldDecreaseIndentAfterEmit) {
4570                    decreaseIndent();
4571                    shouldDecreaseIndentAfterEmit = false;
4572                }
4573
4574                previousSibling = child;
4575            }
4576
4577            // Write a trailing comma, if requested.
4578            const emitFlags = previousSibling ? getEmitFlags(previousSibling) : 0;
4579            const skipTrailingComments = commentsDisabled || !!(emitFlags & EmitFlags.NoTrailingComments);
4580            const emitTrailingComma = hasTrailingComma && (format & ListFormat.AllowTrailingComma) && (format & ListFormat.CommaDelimited);
4581            if (emitTrailingComma) {
4582                if (previousSibling && !skipTrailingComments) {
4583                    emitTokenWithComment(SyntaxKind.CommaToken, previousSibling.end, writePunctuation, previousSibling);
4584                }
4585                else {
4586                    writePunctuation(",");
4587                }
4588            }
4589
4590            // Emit any trailing comment of the last element in the list
4591            // i.e
4592            //       var array = [...
4593            //          2
4594            //          /* end of element 2 */
4595            //       ];
4596            if (previousSibling && (parentNode ? parentNode.end : -1) !== previousSibling.end && (format & ListFormat.DelimitersMask) && !skipTrailingComments) {
4597                emitLeadingCommentsOfPosition(emitTrailingComma && childrenTextRange?.end ? childrenTextRange.end : previousSibling.end);
4598            }
4599
4600            // Decrease the indent, if requested.
4601            if (format & ListFormat.Indented) {
4602                decreaseIndent();
4603            }
4604
4605            recordBundleFileInternalSectionEnd(previousSourceFileTextKind);
4606
4607            // Write the closing line terminator or closing whitespace.
4608            const closingLineTerminatorCount = getClosingLineTerminatorCount(parentNode, children[start + count - 1], format, childrenTextRange);
4609            if (closingLineTerminatorCount) {
4610                writeLine(closingLineTerminatorCount);
4611            }
4612            else if (format & (ListFormat.SpaceAfterList | ListFormat.SpaceBetweenBraces)) {
4613                writeSpace();
4614            }
4615        }
4616
4617        // Writers
4618
4619        function writeLiteral(s: string) {
4620            writer.writeLiteral(s);
4621        }
4622
4623        function writeStringLiteral(s: string) {
4624            writer.writeStringLiteral(s);
4625        }
4626
4627        function writeBase(s: string) {
4628            writer.write(s);
4629        }
4630
4631        function writeSymbol(s: string, sym: Symbol) {
4632            writer.writeSymbol(s, sym);
4633        }
4634
4635        function writePunctuation(s: string) {
4636            writer.writePunctuation(s);
4637        }
4638
4639        function writeTrailingSemicolon() {
4640            writer.writeTrailingSemicolon(";");
4641        }
4642
4643        function writeKeyword(s: string) {
4644            writer.writeKeyword(s);
4645        }
4646
4647        function writeOperator(s: string) {
4648            writer.writeOperator(s);
4649        }
4650
4651        function writeParameter(s: string) {
4652            writer.writeParameter(s);
4653        }
4654
4655        function writeComment(s: string) {
4656            writer.writeComment(s);
4657        }
4658
4659        function writeSpace() {
4660            writer.writeSpace(" ");
4661        }
4662
4663        function writeProperty(s: string) {
4664            writer.writeProperty(s);
4665        }
4666
4667        function nonEscapingWrite(s: string) {
4668            // This should be defined in a snippet-escaping text writer.
4669            if (writer.nonEscapingWrite) {
4670                writer.nonEscapingWrite(s);
4671            }
4672            else {
4673                writer.write(s);
4674            }
4675        }
4676
4677        function writeLine(count = 1) {
4678            for (let i = 0; i < count; i++) {
4679                writer.writeLine(i > 0);
4680            }
4681        }
4682
4683        function increaseIndent() {
4684            writer.increaseIndent();
4685        }
4686
4687        function decreaseIndent() {
4688            writer.decreaseIndent();
4689        }
4690
4691        function writeToken(token: SyntaxKind, pos: number, writer: (s: string) => void, contextNode?: Node) {
4692            return !sourceMapsDisabled
4693                ? emitTokenWithSourceMap(contextNode, token, writer, pos, writeTokenText)
4694                : writeTokenText(token, writer, pos);
4695        }
4696
4697        function writeTokenNode(node: Node, writer: (s: string) => void) {
4698            if (onBeforeEmitToken) {
4699                onBeforeEmitToken(node);
4700            }
4701            writer(tokenToString(node.kind)!);
4702            if (onAfterEmitToken) {
4703                onAfterEmitToken(node);
4704            }
4705        }
4706
4707        function writeTokenText(token: SyntaxKind, writer: (s: string) => void): void;
4708        function writeTokenText(token: SyntaxKind, writer: (s: string) => void, pos: number): number;
4709        function writeTokenText(token: SyntaxKind, writer: (s: string) => void, pos?: number): number {
4710            const tokenString = tokenToString(token)!;
4711            writer(tokenString);
4712            return pos! < 0 ? pos! : pos! + tokenString.length;
4713        }
4714
4715        function writeLineOrSpace(parentNode: Node, prevChildNode: Node, nextChildNode: Node) {
4716            if (getEmitFlags(parentNode) & EmitFlags.SingleLine) {
4717                writeSpace();
4718            }
4719            else if (preserveSourceNewlines) {
4720                const lines = getLinesBetweenNodes(parentNode, prevChildNode, nextChildNode);
4721                if (lines) {
4722                    writeLine(lines);
4723                }
4724                else {
4725                    writeSpace();
4726                }
4727            }
4728            else {
4729                writeLine();
4730            }
4731        }
4732
4733        function writeLines(text: string): void {
4734            const lines = text.split(/\r\n?|\n/g);
4735            const indentation = guessIndentation(lines);
4736            for (const lineText of lines) {
4737                const line = indentation ? lineText.slice(indentation) : lineText;
4738                if (line.length) {
4739                    writeLine();
4740                    write(line);
4741                }
4742            }
4743        }
4744
4745        function writeLinesAndIndent(lineCount: number, writeSpaceIfNotIndenting: boolean) {
4746            if (lineCount) {
4747                increaseIndent();
4748                writeLine(lineCount);
4749            }
4750            else if (writeSpaceIfNotIndenting) {
4751                writeSpace();
4752            }
4753        }
4754
4755        // Helper function to decrease the indent if we previously indented.  Allows multiple
4756        // previous indent values to be considered at a time.  This also allows caller to just
4757        // call this once, passing in all their appropriate indent values, instead of needing
4758        // to call this helper function multiple times.
4759        function decreaseIndentIf(value1: boolean | number | undefined, value2?: boolean | number) {
4760            if (value1) {
4761                decreaseIndent();
4762            }
4763            if (value2) {
4764                decreaseIndent();
4765            }
4766        }
4767
4768        function getLeadingLineTerminatorCount(parentNode: Node | undefined, firstChild: Node | undefined, format: ListFormat): number {
4769            if (format & ListFormat.PreserveLines || preserveSourceNewlines) {
4770                if (format & ListFormat.PreferNewLine) {
4771                    return 1;
4772                }
4773
4774                if (firstChild === undefined) {
4775                    return !parentNode || currentSourceFile && rangeIsOnSingleLine(parentNode, currentSourceFile) ? 0 : 1;
4776                }
4777                if (firstChild.pos === nextListElementPos) {
4778                    // If this child starts at the beginning of a list item in a parent list, its leading
4779                    // line terminators have already been written as the separating line terminators of the
4780                    // parent list. Example:
4781                    //
4782                    // class Foo {
4783                    //   constructor() {}
4784                    //   public foo() {}
4785                    // }
4786                    //
4787                    // The outer list is the list of class members, with one line terminator between the
4788                    // constructor and the method. The constructor is written, the separating line terminator
4789                    // is written, and then we start emitting the method. Its modifiers ([public]) constitute an inner
4790                    // list, so we look for its leading line terminators. If we didn't know that we had already
4791                    // written a newline as part of the parent list, it would appear that we need to write a
4792                    // leading newline to start the modifiers.
4793                    return 0;
4794                }
4795                if (firstChild.kind === SyntaxKind.JsxText) {
4796                    // JsxText will be written with its leading whitespace, so don't add more manually.
4797                    return 0;
4798                }
4799                if (currentSourceFile && parentNode &&
4800                    !positionIsSynthesized(parentNode.pos) &&
4801                    !nodeIsSynthesized(firstChild) &&
4802                    (!firstChild.parent || getOriginalNode(firstChild.parent) === getOriginalNode(parentNode))
4803                ) {
4804                    if (preserveSourceNewlines) {
4805                        return getEffectiveLines(
4806                            includeComments => getLinesBetweenPositionAndPrecedingNonWhitespaceCharacter(
4807                                firstChild.pos,
4808                                parentNode.pos,
4809                                currentSourceFile!,
4810                                includeComments));
4811                    }
4812                    return rangeStartPositionsAreOnSameLine(parentNode, firstChild, currentSourceFile) ? 0 : 1;
4813                }
4814                if (synthesizedNodeStartsOnNewLine(firstChild, format)) {
4815                    return 1;
4816                }
4817            }
4818            return format & ListFormat.MultiLine ? 1 : 0;
4819        }
4820
4821        function getSeparatingLineTerminatorCount(previousNode: Node | undefined, nextNode: Node, format: ListFormat): number {
4822            if (format & ListFormat.PreserveLines || preserveSourceNewlines) {
4823                if (previousNode === undefined || nextNode === undefined) {
4824                    return 0;
4825                }
4826                if (nextNode.kind === SyntaxKind.JsxText) {
4827                    // JsxText will be written with its leading whitespace, so don't add more manually.
4828                    return 0;
4829                }
4830                else if (currentSourceFile && !nodeIsSynthesized(previousNode) && !nodeIsSynthesized(nextNode)) {
4831                    if (preserveSourceNewlines && siblingNodePositionsAreComparable(previousNode, nextNode)) {
4832                        return getEffectiveLines(
4833                            includeComments => getLinesBetweenRangeEndAndRangeStart(
4834                                previousNode,
4835                                nextNode,
4836                                currentSourceFile!,
4837                                includeComments));
4838                    }
4839                    // If `preserveSourceNewlines` is `false` we do not intend to preserve the effective lines between the
4840                    // previous and next node. Instead we naively check whether nodes are on separate lines within the
4841                    // same node parent. If so, we intend to preserve a single line terminator. This is less precise and
4842                    // expensive than checking with `preserveSourceNewlines` as above, but the goal is not to preserve the
4843                    // effective source lines between two sibling nodes.
4844                    else if (!preserveSourceNewlines && originalNodesHaveSameParent(previousNode, nextNode)) {
4845                        return rangeEndIsOnSameLineAsRangeStart(previousNode, nextNode, currentSourceFile) ? 0 : 1;
4846                    }
4847                    // If the two nodes are not comparable, add a line terminator based on the format that can indicate
4848                    // whether new lines are preferred or not.
4849                    return format & ListFormat.PreferNewLine ? 1 : 0;
4850                }
4851                else if (synthesizedNodeStartsOnNewLine(previousNode, format) || synthesizedNodeStartsOnNewLine(nextNode, format)) {
4852                    return 1;
4853                }
4854            }
4855            else if (getStartsOnNewLine(nextNode)) {
4856                return 1;
4857            }
4858            return format & ListFormat.MultiLine ? 1 : 0;
4859        }
4860
4861        function getClosingLineTerminatorCount(parentNode: Node | undefined, lastChild: Node | undefined, format: ListFormat, childrenTextRange: TextRange | undefined): number {
4862            if (format & ListFormat.PreserveLines || preserveSourceNewlines) {
4863                if (format & ListFormat.PreferNewLine) {
4864                    return 1;
4865                }
4866
4867                if (lastChild === undefined) {
4868                    return !parentNode || currentSourceFile && rangeIsOnSingleLine(parentNode, currentSourceFile) ? 0 : 1;
4869                }
4870                if (currentSourceFile && parentNode && !positionIsSynthesized(parentNode.pos) && !nodeIsSynthesized(lastChild) && (!lastChild.parent || lastChild.parent === parentNode)) {
4871                    if (preserveSourceNewlines) {
4872                        const end = childrenTextRange && !positionIsSynthesized(childrenTextRange.end) ? childrenTextRange.end : lastChild.end;
4873                        return getEffectiveLines(
4874                            includeComments => getLinesBetweenPositionAndNextNonWhitespaceCharacter(
4875                                end,
4876                                parentNode.end,
4877                                currentSourceFile!,
4878                                includeComments));
4879                    }
4880                    return rangeEndPositionsAreOnSameLine(parentNode, lastChild, currentSourceFile) ? 0 : 1;
4881                }
4882                if (synthesizedNodeStartsOnNewLine(lastChild, format)) {
4883                    return 1;
4884                }
4885            }
4886            if (format & ListFormat.MultiLine && !(format & ListFormat.NoTrailingNewLine)) {
4887                return 1;
4888            }
4889            return 0;
4890        }
4891
4892        function getEffectiveLines(getLineDifference: (includeComments: boolean) => number) {
4893            // If 'preserveSourceNewlines' is disabled, we should never call this function
4894            // because it could be more expensive than alternative approximations.
4895            Debug.assert(!!preserveSourceNewlines);
4896            // We start by measuring the line difference from a position to its adjacent comments,
4897            // so that this is counted as a one-line difference, not two:
4898            //
4899            //   node1;
4900            //   // NODE2 COMMENT
4901            //   node2;
4902            const lines = getLineDifference(/*includeComments*/ true);
4903            if (lines === 0) {
4904                // However, if the line difference considering comments was 0, we might have this:
4905                //
4906                //   node1; // NODE2 COMMENT
4907                //   node2;
4908                //
4909                // in which case we should be ignoring node2's comment, so this too is counted as
4910                // a one-line difference, not zero.
4911                return getLineDifference(/*includeComments*/ false);
4912            }
4913            return lines;
4914        }
4915
4916        function writeLineSeparatorsAndIndentBefore(node: Node, parent: Node): boolean {
4917            const leadingNewlines = preserveSourceNewlines && getLeadingLineTerminatorCount(parent, node, ListFormat.None);
4918            if (leadingNewlines) {
4919                writeLinesAndIndent(leadingNewlines, /*writeSpaceIfNotIndenting*/ false);
4920            }
4921            return !!leadingNewlines;
4922        }
4923
4924        function writeLineSeparatorsAfter(node: Node, parent: Node) {
4925            const trailingNewlines = preserveSourceNewlines && getClosingLineTerminatorCount(parent, node, ListFormat.None, /*childrenTextRange*/ undefined);
4926            if (trailingNewlines) {
4927                writeLine(trailingNewlines);
4928            }
4929        }
4930
4931        function synthesizedNodeStartsOnNewLine(node: Node, format: ListFormat) {
4932            if (nodeIsSynthesized(node)) {
4933                const startsOnNewLine = getStartsOnNewLine(node);
4934                if (startsOnNewLine === undefined) {
4935                    return (format & ListFormat.PreferNewLine) !== 0;
4936                }
4937
4938                return startsOnNewLine;
4939            }
4940
4941            return (format & ListFormat.PreferNewLine) !== 0;
4942        }
4943
4944        function getLinesBetweenNodes(parent: Node, node1: Node, node2: Node): number {
4945            if (getEmitFlags(parent) & EmitFlags.NoIndentation) {
4946                return 0;
4947            }
4948
4949            parent = skipSynthesizedParentheses(parent);
4950            node1 = skipSynthesizedParentheses(node1);
4951            node2 = skipSynthesizedParentheses(node2);
4952
4953            // Always use a newline for synthesized code if the synthesizer desires it.
4954            if (getStartsOnNewLine(node2)) {
4955                return 1;
4956            }
4957
4958            if (currentSourceFile && !nodeIsSynthesized(parent) && !nodeIsSynthesized(node1) && !nodeIsSynthesized(node2)) {
4959                if (preserveSourceNewlines) {
4960                    return getEffectiveLines(
4961                        includeComments => getLinesBetweenRangeEndAndRangeStart(
4962                            node1,
4963                            node2,
4964                            currentSourceFile!,
4965                            includeComments));
4966                }
4967                return rangeEndIsOnSameLineAsRangeStart(node1, node2, currentSourceFile) ? 0 : 1;
4968            }
4969
4970            return 0;
4971        }
4972
4973        function isEmptyBlock(block: BlockLike) {
4974            return block.statements.length === 0
4975                && (!currentSourceFile || rangeEndIsOnSameLineAsRangeStart(block, block, currentSourceFile));
4976        }
4977
4978        function skipSynthesizedParentheses(node: Node) {
4979            while (node.kind === SyntaxKind.ParenthesizedExpression && nodeIsSynthesized(node)) {
4980                node = (node as ParenthesizedExpression).expression;
4981            }
4982
4983            return node;
4984        }
4985
4986        function getTextOfNode(node: Identifier | PrivateIdentifier | LiteralExpression, includeTrivia?: boolean): string {
4987            if (isGeneratedIdentifier(node) || isGeneratedPrivateIdentifier(node)) {
4988                return generateName(node);
4989            }
4990            if (isStringLiteral(node) && node.textSourceNode) {
4991                return getTextOfNode(node.textSourceNode, includeTrivia);
4992            }
4993            const sourceFile = currentSourceFile; // const needed for control flow
4994            const canUseSourceFile = !!sourceFile && !!node.parent && !nodeIsSynthesized(node);
4995            if (isMemberName(node)) {
4996                if (!canUseSourceFile || getSourceFileOfNode(node) !== getOriginalNode(sourceFile)) {
4997                    return idText(node);
4998                }
4999            }
5000            else {
5001                Debug.assertNode(node, isLiteralExpression); // not strictly necessary
5002                if (!canUseSourceFile) {
5003                    return node.text;
5004                }
5005            }
5006            return getSourceTextOfNodeFromSourceFile(sourceFile, node, includeTrivia);
5007        }
5008
5009        function getLiteralTextOfNode(node: LiteralLikeNode, neverAsciiEscape: boolean | undefined, jsxAttributeEscape: boolean): string {
5010            if (node.kind === SyntaxKind.StringLiteral && (node as StringLiteral).textSourceNode) {
5011                const textSourceNode = (node as StringLiteral).textSourceNode!;
5012                if (isIdentifier(textSourceNode) || isPrivateIdentifier(textSourceNode) || isNumericLiteral(textSourceNode)) {
5013                    const text = isNumericLiteral(textSourceNode) ? textSourceNode.text : getTextOfNode(textSourceNode);
5014                    return jsxAttributeEscape ? `"${escapeJsxAttributeString(text)}"` :
5015                        neverAsciiEscape || (getEmitFlags(node) & EmitFlags.NoAsciiEscaping) ? `"${escapeString(text)}"` :
5016                        `"${escapeNonAsciiString(text)}"`;
5017                }
5018                else {
5019                    return getLiteralTextOfNode(textSourceNode, neverAsciiEscape, jsxAttributeEscape);
5020                }
5021            }
5022
5023            const flags = (neverAsciiEscape ? GetLiteralTextFlags.NeverAsciiEscape : 0)
5024                | (jsxAttributeEscape ? GetLiteralTextFlags.JsxAttributeEscape : 0)
5025                | (printerOptions.terminateUnterminatedLiterals ? GetLiteralTextFlags.TerminateUnterminatedLiterals : 0)
5026                | (printerOptions.target && printerOptions.target === ScriptTarget.ESNext ? GetLiteralTextFlags.AllowNumericSeparator : 0);
5027
5028            return getLiteralText(node, currentSourceFile, flags);
5029        }
5030
5031        /**
5032         * Push a new name generation scope.
5033         */
5034        function pushNameGenerationScope(node: Node | undefined) {
5035            if (node && getEmitFlags(node) & EmitFlags.ReuseTempVariableScope) {
5036                return;
5037            }
5038            tempFlagsStack.push(tempFlags);
5039            tempFlags = TempFlags.Auto;
5040            privateNameTempFlagsStack.push(privateNameTempFlags);
5041            privateNameTempFlags = TempFlags.Auto;
5042            formattedNameTempFlagsStack.push(formattedNameTempFlags);
5043            formattedNameTempFlags = undefined;
5044            reservedNamesStack.push(reservedNames);
5045        }
5046
5047        /**
5048         * Pop the current name generation scope.
5049         */
5050        function popNameGenerationScope(node: Node | undefined) {
5051            if (node && getEmitFlags(node) & EmitFlags.ReuseTempVariableScope) {
5052                return;
5053            }
5054            tempFlags = tempFlagsStack.pop()!;
5055            privateNameTempFlags = privateNameTempFlagsStack.pop()!;
5056            formattedNameTempFlags = formattedNameTempFlagsStack.pop();
5057            reservedNames = reservedNamesStack.pop()!;
5058        }
5059
5060        function reserveNameInNestedScopes(name: string) {
5061            if (!reservedNames || reservedNames === lastOrUndefined(reservedNamesStack)) {
5062                reservedNames = new Set();
5063            }
5064            reservedNames.add(name);
5065        }
5066
5067        function generateNames(node: Node | undefined) {
5068            if (!node) return;
5069            switch (node.kind) {
5070                case SyntaxKind.Block:
5071                    forEach((node as Block).statements, generateNames);
5072                    break;
5073                case SyntaxKind.LabeledStatement:
5074                case SyntaxKind.WithStatement:
5075                case SyntaxKind.DoStatement:
5076                case SyntaxKind.WhileStatement:
5077                    generateNames((node as LabeledStatement | WithStatement | DoStatement | WhileStatement).statement);
5078                    break;
5079                case SyntaxKind.IfStatement:
5080                    generateNames((node as IfStatement).thenStatement);
5081                    generateNames((node as IfStatement).elseStatement);
5082                    break;
5083                case SyntaxKind.ForStatement:
5084                case SyntaxKind.ForOfStatement:
5085                case SyntaxKind.ForInStatement:
5086                    generateNames((node as ForStatement | ForInOrOfStatement).initializer);
5087                    generateNames((node as ForStatement | ForInOrOfStatement).statement);
5088                    break;
5089                case SyntaxKind.SwitchStatement:
5090                    generateNames((node as SwitchStatement).caseBlock);
5091                    break;
5092                case SyntaxKind.CaseBlock:
5093                    forEach((node as CaseBlock).clauses, generateNames);
5094                    break;
5095                case SyntaxKind.CaseClause:
5096                case SyntaxKind.DefaultClause:
5097                    forEach((node as CaseOrDefaultClause).statements, generateNames);
5098                    break;
5099                case SyntaxKind.TryStatement:
5100                    generateNames((node as TryStatement).tryBlock);
5101                    generateNames((node as TryStatement).catchClause);
5102                    generateNames((node as TryStatement).finallyBlock);
5103                    break;
5104                case SyntaxKind.CatchClause:
5105                    generateNames((node as CatchClause).variableDeclaration);
5106                    generateNames((node as CatchClause).block);
5107                    break;
5108                case SyntaxKind.VariableStatement:
5109                    generateNames((node as VariableStatement).declarationList);
5110                    break;
5111                case SyntaxKind.VariableDeclarationList:
5112                    forEach((node as VariableDeclarationList).declarations, generateNames);
5113                    break;
5114                case SyntaxKind.VariableDeclaration:
5115                case SyntaxKind.Parameter:
5116                case SyntaxKind.BindingElement:
5117                case SyntaxKind.ClassDeclaration:
5118                    generateNameIfNeeded((node as NamedDeclaration).name);
5119                    break;
5120                case SyntaxKind.FunctionDeclaration:
5121                    generateNameIfNeeded((node as FunctionDeclaration).name);
5122                    if (getEmitFlags(node) & EmitFlags.ReuseTempVariableScope) {
5123                        forEach((node as FunctionDeclaration).parameters, generateNames);
5124                        generateNames((node as FunctionDeclaration).body);
5125                    }
5126                    break;
5127                case SyntaxKind.ObjectBindingPattern:
5128                case SyntaxKind.ArrayBindingPattern:
5129                    forEach((node as BindingPattern).elements, generateNames);
5130                    break;
5131                case SyntaxKind.ImportDeclaration:
5132                    generateNames((node as ImportDeclaration).importClause);
5133                    break;
5134                case SyntaxKind.ImportClause:
5135                    generateNameIfNeeded((node as ImportClause).name);
5136                    generateNames((node as ImportClause).namedBindings);
5137                    break;
5138                case SyntaxKind.NamespaceImport:
5139                    generateNameIfNeeded((node as NamespaceImport).name);
5140                    break;
5141                case SyntaxKind.NamespaceExport:
5142                    generateNameIfNeeded((node as NamespaceExport).name);
5143                    break;
5144                case SyntaxKind.NamedImports:
5145                    forEach((node as NamedImports).elements, generateNames);
5146                    break;
5147                case SyntaxKind.ImportSpecifier:
5148                    generateNameIfNeeded((node as ImportSpecifier).propertyName || (node as ImportSpecifier).name);
5149                    break;
5150            }
5151        }
5152
5153        function generateMemberNames(node: Node | undefined) {
5154            if (!node) return;
5155            switch (node.kind) {
5156                case SyntaxKind.PropertyAssignment:
5157                case SyntaxKind.ShorthandPropertyAssignment:
5158                case SyntaxKind.PropertyDeclaration:
5159                case SyntaxKind.MethodDeclaration:
5160                case SyntaxKind.GetAccessor:
5161                case SyntaxKind.SetAccessor:
5162                    generateNameIfNeeded((node as NamedDeclaration).name);
5163                    break;
5164            }
5165        }
5166
5167        function generateNameIfNeeded(name: DeclarationName | undefined) {
5168            if (name) {
5169                if (isGeneratedIdentifier(name) || isGeneratedPrivateIdentifier(name)) {
5170                    generateName(name);
5171                }
5172                else if (isBindingPattern(name)) {
5173                    generateNames(name);
5174                }
5175            }
5176        }
5177
5178        /**
5179         * Generate the text for a generated identifier.
5180         */
5181        function generateName(name: GeneratedIdentifier | GeneratedPrivateIdentifier) {
5182            if ((name.autoGenerateFlags & GeneratedIdentifierFlags.KindMask) === GeneratedIdentifierFlags.Node) {
5183                // Node names generate unique names based on their original node
5184                // and are cached based on that node's id.
5185                return generateNameCached(getNodeForGeneratedName(name), isPrivateIdentifier(name), name.autoGenerateFlags, name.autoGeneratePrefix, name.autoGenerateSuffix);
5186            }
5187            else {
5188                // Auto, Loop, and Unique names are cached based on their unique
5189                // autoGenerateId.
5190                const autoGenerateId = name.autoGenerateId!;
5191                return autoGeneratedIdToGeneratedName[autoGenerateId] || (autoGeneratedIdToGeneratedName[autoGenerateId] = makeName(name));
5192            }
5193        }
5194
5195        function generateNameCached(node: Node, privateName: boolean, flags?: GeneratedIdentifierFlags, prefix?: string | GeneratedNamePart, suffix?: string) {
5196            const nodeId = getNodeId(node);
5197            return nodeIdToGeneratedName[nodeId] || (nodeIdToGeneratedName[nodeId] = generateNameForNode(node, privateName, flags ?? GeneratedIdentifierFlags.None, formatGeneratedNamePart(prefix, generateName), formatGeneratedNamePart(suffix)));
5198        }
5199
5200        /**
5201         * Returns a value indicating whether a name is unique globally, within the current file,
5202         * or within the NameGenerator.
5203         */
5204        function isUniqueName(name: string): boolean {
5205            return isFileLevelUniqueName(name)
5206                && !generatedNames.has(name)
5207                && !(reservedNames && reservedNames.has(name));
5208        }
5209
5210        /**
5211         * Returns a value indicating whether a name is unique globally or within the current file.
5212         */
5213        function isFileLevelUniqueName(name: string) {
5214            return currentSourceFile ? ts.isFileLevelUniqueName(currentSourceFile, name, hasGlobalName) : true;
5215        }
5216
5217        /**
5218         * Returns a value indicating whether a name is unique within a container.
5219         */
5220        function isUniqueLocalName(name: string, container: Node): boolean {
5221            for (let node = container; isNodeDescendantOf(node, container); node = node.nextContainer!) {
5222                if (node.locals) {
5223                    const local = node.locals.get(escapeLeadingUnderscores(name));
5224                    // We conservatively include alias symbols to cover cases where they're emitted as locals
5225                    if (local && local.flags & (SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias)) {
5226                        return false;
5227                    }
5228                }
5229            }
5230            return true;
5231        }
5232
5233        function getTempFlags(formattedNameKey: string) {
5234            switch (formattedNameKey) {
5235                case "":
5236                    return tempFlags;
5237                case "#":
5238                    return privateNameTempFlags;
5239                default:
5240                    return formattedNameTempFlags?.get(formattedNameKey) ?? TempFlags.Auto;
5241            }
5242        }
5243
5244        function setTempFlags(formattedNameKey: string, flags: TempFlags) {
5245            switch (formattedNameKey) {
5246                case "":
5247                    tempFlags = flags;
5248                    break;
5249                case "#":
5250                    privateNameTempFlags = flags;
5251                    break;
5252                default:
5253                    formattedNameTempFlags ??= new Map();
5254                    formattedNameTempFlags.set(formattedNameKey, flags);
5255                    break;
5256            }
5257        }
5258
5259        /**
5260         * Return the next available name in the pattern _a ... _z, _0, _1, ...
5261         * TempFlags._i or TempFlags._n may be used to express a preference for that dedicated name.
5262         * Note that names generated by makeTempVariableName and makeUniqueName will never conflict.
5263         */
5264        function makeTempVariableName(flags: TempFlags, reservedInNestedScopes: boolean, privateName: boolean, prefix: string, suffix: string): string {
5265            if (prefix.length > 0 && prefix.charCodeAt(0) === CharacterCodes.hash) {
5266                prefix = prefix.slice(1);
5267            }
5268
5269            // Generate a key to use to acquire a TempFlags counter based on the fixed portions of the generated name.
5270            const key = formatGeneratedName(privateName, prefix, "", suffix);
5271            let tempFlags = getTempFlags(key);
5272
5273            if (flags && !(tempFlags & flags)) {
5274                const name = flags === TempFlags._i ? "_i" : "_n";
5275                const fullName = formatGeneratedName(privateName, prefix, name, suffix);
5276                if (isUniqueName(fullName)) {
5277                    tempFlags |= flags;
5278                    if (reservedInNestedScopes) {
5279                        reserveNameInNestedScopes(fullName);
5280                    }
5281                    setTempFlags(key, tempFlags);
5282                    return fullName;
5283                }
5284            }
5285
5286            while (true) {
5287                const count = tempFlags & TempFlags.CountMask;
5288                tempFlags++;
5289                // Skip over 'i' and 'n'
5290                if (count !== 8 && count !== 13) {
5291                    const name = count < 26
5292                        ? "_" + String.fromCharCode(CharacterCodes.a + count)
5293                        : "_" + (count - 26);
5294                    const fullName = formatGeneratedName(privateName, prefix, name, suffix);
5295                    if (isUniqueName(fullName)) {
5296                        if (reservedInNestedScopes) {
5297                            reserveNameInNestedScopes(fullName);
5298                        }
5299                        setTempFlags(key, tempFlags);
5300                        return fullName;
5301                    }
5302                }
5303            }
5304        }
5305
5306        /**
5307         * Generate a name that is unique within the current file and doesn't conflict with any names
5308         * in global scope. The name is formed by adding an '_n' suffix to the specified base name,
5309         * where n is a positive integer. Note that names generated by makeTempVariableName and
5310         * makeUniqueName are guaranteed to never conflict.
5311         * If `optimistic` is set, the first instance will use 'baseName' verbatim instead of 'baseName_1'
5312         */
5313        function makeUniqueName(baseName: string, checkFn: (name: string) => boolean = isUniqueName, optimistic: boolean, scoped: boolean, privateName: boolean, prefix: string, suffix: string): string {
5314            if (baseName.length > 0 && baseName.charCodeAt(0) === CharacterCodes.hash) {
5315                baseName = baseName.slice(1);
5316            }
5317            if (prefix.length > 0 && prefix.charCodeAt(0) === CharacterCodes.hash) {
5318                prefix = prefix.slice(1);
5319            }
5320            if (optimistic) {
5321                const fullName = formatGeneratedName(privateName, prefix, baseName, suffix);
5322                if (checkFn(fullName)) {
5323                    if (scoped) {
5324                        reserveNameInNestedScopes(fullName);
5325                    }
5326                    else {
5327                        generatedNames.add(fullName);
5328                    }
5329                    return fullName;
5330                }
5331            }
5332            // Find the first unique 'name_n', where n is a positive number
5333            if (baseName.charCodeAt(baseName.length - 1) !== CharacterCodes._) {
5334                baseName += "_";
5335            }
5336            let i = 1;
5337            while (true) {
5338                const fullName = formatGeneratedName(privateName, prefix, baseName + i, suffix);
5339                if (checkFn(fullName)) {
5340                    if (scoped) {
5341                        reserveNameInNestedScopes(fullName);
5342                    }
5343                    else {
5344                        generatedNames.add(fullName);
5345                    }
5346                    return fullName;
5347                }
5348                i++;
5349            }
5350        }
5351
5352        function makeFileLevelOptimisticUniqueName(name: string) {
5353            return makeUniqueName(name, isFileLevelUniqueName, /*optimistic*/ true, /*scoped*/ false, /*privateName*/ false, /*prefix*/ "", /*suffix*/ "");
5354        }
5355
5356        /**
5357         * Generates a unique name for a ModuleDeclaration or EnumDeclaration.
5358         */
5359        function generateNameForModuleOrEnum(node: ModuleDeclaration | EnumDeclaration) {
5360            const name = getTextOfNode(node.name);
5361            // Use module/enum name itself if it is unique, otherwise make a unique variation
5362            return isUniqueLocalName(name, node) ? name : makeUniqueName(name, isUniqueName, /*optimistic*/ false, /*scoped*/ false, /*privateName*/ false, /*prefix*/ "", /*suffix*/ "");
5363        }
5364
5365        /**
5366         * Generates a unique name for an ImportDeclaration or ExportDeclaration.
5367         */
5368        function generateNameForImportOrExportDeclaration(node: ImportDeclaration | ExportDeclaration) {
5369            const expr = getExternalModuleName(node)!; // TODO: GH#18217
5370            const baseName = isStringLiteral(expr) ?
5371                makeIdentifierFromModuleName(expr.text) : "module";
5372            return makeUniqueName(baseName, isUniqueName, /*optimistic*/ false, /*scoped*/ false, /*privateName*/ false, /*prefix*/ "", /*suffix*/ "");
5373        }
5374
5375        /**
5376         * Generates a unique name for a default export.
5377         */
5378        function generateNameForExportDefault() {
5379            return makeUniqueName("default", isUniqueName, /*optimistic*/ false, /*scoped*/ false, /*privateName*/ false, /*prefix*/ "", /*suffix*/ "");
5380        }
5381
5382        /**
5383         * Generates a unique name for a class expression.
5384         */
5385        function generateNameForClassExpression() {
5386            return makeUniqueName("class", isUniqueName, /*optimistic*/ false, /*scoped*/ false, /*privateName*/ false, /*prefix*/ "", /*suffix*/ "");
5387        }
5388
5389        function generateNameForMethodOrAccessor(node: MethodDeclaration | AccessorDeclaration, privateName: boolean, prefix: string, suffix: string) {
5390            if (isIdentifier(node.name)) {
5391                return generateNameCached(node.name, privateName);
5392            }
5393            return makeTempVariableName(TempFlags.Auto, /*reservedInNestedScopes*/ false, privateName, prefix, suffix);
5394        }
5395
5396        /**
5397         * Generates a unique name from a node.
5398         */
5399        function generateNameForNode(node: Node, privateName: boolean, flags: GeneratedIdentifierFlags, prefix: string, suffix: string): string {
5400            switch (node.kind) {
5401                case SyntaxKind.Identifier:
5402                case SyntaxKind.PrivateIdentifier:
5403                    return makeUniqueName(
5404                        getTextOfNode(node as Identifier),
5405                        isUniqueName,
5406                        !!(flags & GeneratedIdentifierFlags.Optimistic),
5407                        !!(flags & GeneratedIdentifierFlags.ReservedInNestedScopes),
5408                        privateName,
5409                        prefix,
5410                        suffix
5411                    );
5412                case SyntaxKind.ModuleDeclaration:
5413                case SyntaxKind.EnumDeclaration:
5414                    Debug.assert(!prefix && !suffix && !privateName);
5415                    return generateNameForModuleOrEnum(node as ModuleDeclaration | EnumDeclaration);
5416                case SyntaxKind.ImportDeclaration:
5417                case SyntaxKind.ExportDeclaration:
5418                    Debug.assert(!prefix && !suffix && !privateName);
5419                    return generateNameForImportOrExportDeclaration(node as ImportDeclaration | ExportDeclaration);
5420                case SyntaxKind.FunctionDeclaration:
5421                case SyntaxKind.ClassDeclaration:
5422                case SyntaxKind.ExportAssignment:
5423                    Debug.assert(!prefix && !suffix && !privateName);
5424                    return generateNameForExportDefault();
5425                case SyntaxKind.ClassExpression:
5426                    Debug.assert(!prefix && !suffix && !privateName);
5427                    return generateNameForClassExpression();
5428                case SyntaxKind.MethodDeclaration:
5429                case SyntaxKind.GetAccessor:
5430                case SyntaxKind.SetAccessor:
5431                    return generateNameForMethodOrAccessor(node as MethodDeclaration | AccessorDeclaration, privateName, prefix, suffix);
5432                case SyntaxKind.ComputedPropertyName:
5433                    return makeTempVariableName(TempFlags.Auto, /*reserveInNestedScopes*/ true, privateName, prefix, suffix);
5434                default:
5435                    return makeTempVariableName(TempFlags.Auto, /*reserveInNestedScopes*/ false, privateName, prefix, suffix);
5436            }
5437        }
5438
5439        /**
5440         * Generates a unique identifier for a node.
5441         */
5442        function makeName(name: GeneratedIdentifier | GeneratedPrivateIdentifier) {
5443            const prefix = formatGeneratedNamePart(name.autoGeneratePrefix, generateName);
5444            const suffix = formatGeneratedNamePart (name.autoGenerateSuffix);
5445            switch (name.autoGenerateFlags & GeneratedIdentifierFlags.KindMask) {
5446                case GeneratedIdentifierFlags.Auto:
5447                    return makeTempVariableName(TempFlags.Auto, !!(name.autoGenerateFlags & GeneratedIdentifierFlags.ReservedInNestedScopes), isPrivateIdentifier(name), prefix, suffix);
5448                case GeneratedIdentifierFlags.Loop:
5449                    Debug.assertNode(name, isIdentifier);
5450                    return makeTempVariableName(TempFlags._i, !!(name.autoGenerateFlags & GeneratedIdentifierFlags.ReservedInNestedScopes), /*privateName*/ false, prefix, suffix);
5451                case GeneratedIdentifierFlags.Unique:
5452                    return makeUniqueName(
5453                        idText(name),
5454                        (name.autoGenerateFlags & GeneratedIdentifierFlags.FileLevel) ? isFileLevelUniqueName : isUniqueName,
5455                        !!(name.autoGenerateFlags & GeneratedIdentifierFlags.Optimistic),
5456                        !!(name.autoGenerateFlags & GeneratedIdentifierFlags.ReservedInNestedScopes),
5457                        isPrivateIdentifier(name),
5458                        prefix,
5459                        suffix
5460                    );
5461            }
5462
5463            return Debug.fail(`Unsupported GeneratedIdentifierKind: ${Debug.formatEnum(name.autoGenerateFlags & GeneratedIdentifierFlags.KindMask, (ts as any).GeneratedIdentifierFlags, /*isFlags*/ true)}.`);
5464        }
5465
5466        // Comments
5467
5468        function pipelineEmitWithComments(hint: EmitHint, node: Node) {
5469            const pipelinePhase = getNextPipelinePhase(PipelinePhase.Comments, hint, node);
5470            const savedContainerPos = containerPos;
5471            const savedContainerEnd = containerEnd;
5472            const savedDeclarationListContainerEnd = declarationListContainerEnd;
5473            //@ts-ignore
5474            if(removeCommentsCollection == undefined || (removeCommentsCollection && node.name && removeCommentsCollection.includes(node.name.escapedText))) {
5475                emitCommentsBeforeNode(node);
5476            }
5477            pipelinePhase(hint, node);
5478            emitCommentsAfterNode(node, savedContainerPos, savedContainerEnd, savedDeclarationListContainerEnd);
5479        }
5480
5481        function emitCommentsBeforeNode(node: Node) {
5482            const emitFlags = getEmitFlags(node);
5483            const commentRange = getCommentRange(node);
5484
5485            // Emit leading comments
5486            emitLeadingCommentsOfNode(node, emitFlags, commentRange.pos, commentRange.end);
5487            if (emitFlags & EmitFlags.NoNestedComments) {
5488                commentsDisabled = true;
5489            }
5490        }
5491
5492        function emitCommentsAfterNode(node: Node, savedContainerPos: number, savedContainerEnd: number, savedDeclarationListContainerEnd: number) {
5493            const emitFlags = getEmitFlags(node);
5494            const commentRange = getCommentRange(node);
5495
5496            // Emit trailing comments
5497            if (emitFlags & EmitFlags.NoNestedComments) {
5498                commentsDisabled = false;
5499            }
5500            emitTrailingCommentsOfNode(node, emitFlags, commentRange.pos, commentRange.end, savedContainerPos, savedContainerEnd, savedDeclarationListContainerEnd);
5501            const typeNode = getTypeNode(node);
5502            if (typeNode) {
5503                emitTrailingCommentsOfNode(node, emitFlags, typeNode.pos, typeNode.end, savedContainerPos, savedContainerEnd, savedDeclarationListContainerEnd);
5504            }
5505        }
5506
5507        function emitLeadingCommentsOfNode(node: Node, emitFlags: EmitFlags, pos: number, end: number) {
5508            enterComment();
5509            hasWrittenComment = false;
5510
5511            // We have to explicitly check that the node is JsxText because if the compilerOptions.jsx is "preserve" we will not do any transformation.
5512            // It is expensive to walk entire tree just to set one kind of node to have no comments.
5513            const skipLeadingComments = pos < 0 || (emitFlags & EmitFlags.NoLeadingComments) !== 0 || node.kind === SyntaxKind.JsxText;
5514            const skipTrailingComments = end < 0 || (emitFlags & EmitFlags.NoTrailingComments) !== 0 || node.kind === SyntaxKind.JsxText;
5515
5516            // Save current container state on the stack.
5517            if ((pos > 0 || end > 0) && pos !== end) {
5518                // Emit leading comments if the position is not synthesized and the node
5519                // has not opted out from emitting leading comments.
5520                if (!skipLeadingComments) {
5521                    emitLeadingComments(pos, /*isEmittedNode*/ node.kind !== SyntaxKind.NotEmittedStatement);
5522                }
5523
5524                if (!skipLeadingComments || (pos >= 0 && (emitFlags & EmitFlags.NoLeadingComments) !== 0)) {
5525                    // Advance the container position if comments get emitted or if they've been disabled explicitly using NoLeadingComments.
5526                    containerPos = pos;
5527                }
5528
5529                if (!skipTrailingComments || (end >= 0 && (emitFlags & EmitFlags.NoTrailingComments) !== 0)) {
5530                    // As above.
5531                    containerEnd = end;
5532
5533                    // To avoid invalid comment emit in a down-level binding pattern, we
5534                    // keep track of the last declaration list container's end
5535                    if (node.kind === SyntaxKind.VariableDeclarationList) {
5536                        declarationListContainerEnd = end;
5537                    }
5538                }
5539            }
5540            forEach(getSyntheticLeadingComments(node), emitLeadingSynthesizedComment);
5541            exitComment();
5542        }
5543
5544        function emitTrailingCommentsOfNode(node: Node, emitFlags: EmitFlags, pos: number, end: number, savedContainerPos: number, savedContainerEnd: number, savedDeclarationListContainerEnd: number) {
5545            enterComment();
5546            const skipTrailingComments = end < 0 || (emitFlags & EmitFlags.NoTrailingComments) !== 0 || node.kind === SyntaxKind.JsxText;
5547            forEach(getSyntheticTrailingComments(node), emitTrailingSynthesizedComment);
5548            if ((pos > 0 || end > 0) && pos !== end) {
5549                // Restore previous container state.
5550                containerPos = savedContainerPos;
5551                containerEnd = savedContainerEnd;
5552                declarationListContainerEnd = savedDeclarationListContainerEnd;
5553
5554                // Emit trailing comments if the position is not synthesized and the node
5555                // has not opted out from emitting leading comments and is an emitted node.
5556                if (!skipTrailingComments && node.kind !== SyntaxKind.NotEmittedStatement) {
5557                    emitTrailingComments(end);
5558                }
5559            }
5560            exitComment();
5561        }
5562
5563        function emitLeadingSynthesizedComment(comment: SynthesizedComment) {
5564            if (comment.hasLeadingNewline || comment.kind === SyntaxKind.SingleLineCommentTrivia) {
5565                writer.writeLine();
5566            }
5567            writeSynthesizedComment(comment);
5568            if (comment.hasTrailingNewLine || comment.kind === SyntaxKind.SingleLineCommentTrivia) {
5569                writer.writeLine();
5570            }
5571            else {
5572                writer.writeSpace(" ");
5573            }
5574        }
5575
5576        function emitTrailingSynthesizedComment(comment: SynthesizedComment) {
5577            if (!writer.isAtStartOfLine()) {
5578                writer.writeSpace(" ");
5579            }
5580            writeSynthesizedComment(comment);
5581            if (comment.hasTrailingNewLine) {
5582                writer.writeLine();
5583            }
5584        }
5585
5586        function writeSynthesizedComment(comment: SynthesizedComment) {
5587            const text = formatSynthesizedComment(comment);
5588            const lineMap = comment.kind === SyntaxKind.MultiLineCommentTrivia ? computeLineStarts(text) : undefined;
5589            writeCommentRange(text, lineMap!, writer, 0, text.length, newLine);
5590        }
5591
5592        function formatSynthesizedComment(comment: SynthesizedComment) {
5593            return comment.kind === SyntaxKind.MultiLineCommentTrivia
5594                ? `/*${comment.text}*/`
5595                : `//${comment.text}`;
5596        }
5597
5598        function emitBodyWithDetachedComments(node: Node, detachedRange: TextRange, emitCallback: (node: Node) => void) {
5599            enterComment();
5600            const { pos, end } = detachedRange;
5601            const emitFlags = getEmitFlags(node);
5602            const skipLeadingComments = pos < 0 || (emitFlags & EmitFlags.NoLeadingComments) !== 0;
5603            const skipTrailingComments = commentsDisabled || end < 0 || (emitFlags & EmitFlags.NoTrailingComments) !== 0;
5604            if (!skipLeadingComments) {
5605                emitDetachedCommentsAndUpdateCommentsInfo(detachedRange);
5606            }
5607
5608            exitComment();
5609            if (emitFlags & EmitFlags.NoNestedComments && !commentsDisabled) {
5610                commentsDisabled = true;
5611                emitCallback(node);
5612                commentsDisabled = false;
5613            }
5614            else {
5615                emitCallback(node);
5616            }
5617
5618            enterComment();
5619            if (!skipTrailingComments) {
5620                emitLeadingComments(detachedRange.end, /*isEmittedNode*/ true);
5621                if (hasWrittenComment && !writer.isAtStartOfLine()) {
5622                    writer.writeLine();
5623                }
5624            }
5625            exitComment();
5626
5627        }
5628
5629        function originalNodesHaveSameParent(nodeA: Node, nodeB: Node) {
5630            nodeA = getOriginalNode(nodeA);
5631            // For performance, do not call `getOriginalNode` for `nodeB` if `nodeA` doesn't even
5632            // have a parent node.
5633            return nodeA.parent && nodeA.parent === getOriginalNode(nodeB).parent;
5634        }
5635
5636        function siblingNodePositionsAreComparable(previousNode: Node, nextNode: Node) {
5637            if (nextNode.pos < previousNode.end) {
5638                return false;
5639            }
5640
5641            previousNode = getOriginalNode(previousNode);
5642            nextNode = getOriginalNode(nextNode);
5643            const parent = previousNode.parent;
5644            if (!parent || parent !== nextNode.parent) {
5645                return false;
5646            }
5647
5648            const parentNodeArray = getContainingNodeArray(previousNode);
5649            const prevNodeIndex = parentNodeArray?.indexOf(previousNode);
5650            return prevNodeIndex !== undefined && prevNodeIndex > -1 && parentNodeArray!.indexOf(nextNode) === prevNodeIndex + 1;
5651        }
5652
5653        function emitLeadingComments(pos: number, isEmittedNode: boolean) {
5654            hasWrittenComment = false;
5655
5656            if (isEmittedNode) {
5657                if (pos === 0 && currentSourceFile?.isDeclarationFile) {
5658                    forEachLeadingCommentToEmit(pos, emitNonTripleSlashLeadingComment);
5659                }
5660                else {
5661                    forEachLeadingCommentToEmit(pos, emitLeadingComment);
5662                }
5663            }
5664            else if (pos === 0) {
5665                // If the node will not be emitted in JS, remove all the comments(normal, pinned and ///) associated with the node,
5666                // unless it is a triple slash comment at the top of the file.
5667                // For Example:
5668                //      /// <reference-path ...>
5669                //      declare var x;
5670                //      /// <reference-path ...>
5671                //      interface F {}
5672                //  The first /// will NOT be removed while the second one will be removed even though both node will not be emitted
5673                forEachLeadingCommentToEmit(pos, emitTripleSlashLeadingComment);
5674            }
5675        }
5676
5677        function emitTripleSlashLeadingComment(commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) {
5678            if (isTripleSlashComment(commentPos, commentEnd)) {
5679                emitLeadingComment(commentPos, commentEnd, kind, hasTrailingNewLine, rangePos);
5680            }
5681        }
5682
5683        function emitNonTripleSlashLeadingComment(commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) {
5684            if (!isTripleSlashComment(commentPos, commentEnd)) {
5685                emitLeadingComment(commentPos, commentEnd, kind, hasTrailingNewLine, rangePos);
5686            }
5687        }
5688
5689        function shouldWriteComment(text: string, pos: number) {
5690            if (printerOptions.onlyPrintJsDocStyle) {
5691                return (isJSDocLikeText(text, pos) || isPinnedComment(text, pos));
5692            }
5693            return true;
5694        }
5695
5696        function emitLeadingComment(commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) {
5697            if (!currentSourceFile || !shouldWriteComment(currentSourceFile.text, commentPos)) return;
5698            if (!hasWrittenComment) {
5699                emitNewLineBeforeLeadingCommentOfPosition(getCurrentLineMap(), writer, rangePos, commentPos);
5700                hasWrittenComment = true;
5701            }
5702
5703            // Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
5704            emitPos(commentPos);
5705            writeCommentRange(currentSourceFile.text, getCurrentLineMap(), writer, commentPos, commentEnd, newLine);
5706            emitPos(commentEnd);
5707
5708            if (hasTrailingNewLine) {
5709                writer.writeLine();
5710            }
5711            else if (kind === SyntaxKind.MultiLineCommentTrivia) {
5712                writer.writeSpace(" ");
5713            }
5714        }
5715
5716        function emitLeadingCommentsOfPosition(pos: number) {
5717            if (commentsDisabled || pos === -1) {
5718                return;
5719            }
5720
5721            emitLeadingComments(pos, /*isEmittedNode*/ true);
5722        }
5723
5724        function emitTrailingComments(pos: number) {
5725            forEachTrailingCommentToEmit(pos, emitTrailingComment);
5726        }
5727
5728        function emitTrailingComment(commentPos: number, commentEnd: number, _kind: SyntaxKind, hasTrailingNewLine: boolean) {
5729            if (!currentSourceFile || !shouldWriteComment(currentSourceFile.text, commentPos)) return;
5730            // trailing comments are emitted at space/*trailing comment1 */space/*trailing comment2*/
5731            if (!writer.isAtStartOfLine()) {
5732                writer.writeSpace(" ");
5733            }
5734
5735            emitPos(commentPos);
5736            writeCommentRange(currentSourceFile.text, getCurrentLineMap(), writer, commentPos, commentEnd, newLine);
5737            emitPos(commentEnd);
5738
5739            if (hasTrailingNewLine) {
5740                writer.writeLine();
5741            }
5742        }
5743
5744        function emitTrailingCommentsOfPosition(pos: number, prefixSpace?: boolean, forceNoNewline?: boolean) {
5745            if (commentsDisabled) {
5746                return;
5747            }
5748            enterComment();
5749            forEachTrailingCommentToEmit(pos, prefixSpace ? emitTrailingComment : forceNoNewline ? emitTrailingCommentOfPositionNoNewline : emitTrailingCommentOfPosition);
5750            exitComment();
5751        }
5752
5753        function emitTrailingCommentOfPositionNoNewline(commentPos: number, commentEnd: number, kind: SyntaxKind) {
5754            if (!currentSourceFile) return;
5755            // trailing comments of a position are emitted at /*trailing comment1 */space/*trailing comment*/space
5756
5757            emitPos(commentPos);
5758            writeCommentRange(currentSourceFile.text, getCurrentLineMap(), writer, commentPos, commentEnd, newLine);
5759            emitPos(commentEnd);
5760
5761            if (kind === SyntaxKind.SingleLineCommentTrivia) {
5762                writer.writeLine(); // still write a newline for single-line comments, so closing tokens aren't written on the same line
5763            }
5764        }
5765
5766        function emitTrailingCommentOfPosition(commentPos: number, commentEnd: number, _kind: SyntaxKind, hasTrailingNewLine: boolean) {
5767            if(!currentSourceFile) return;
5768            // trailing comments of a position are emitted at /*trailing comment1 */space/*trailing comment*/space
5769
5770            emitPos(commentPos);
5771            writeCommentRange(currentSourceFile.text, getCurrentLineMap(), writer, commentPos, commentEnd, newLine);
5772            emitPos(commentEnd);
5773
5774            if (hasTrailingNewLine) {
5775                writer.writeLine();
5776            }
5777            else {
5778                writer.writeSpace(" ");
5779            }
5780        }
5781
5782        function forEachLeadingCommentToEmit(pos: number, cb: (commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) => void) {
5783            // Emit the leading comments only if the container's pos doesn't match because the container should take care of emitting these comments
5784            if (currentSourceFile && (containerPos === -1 || pos !== containerPos)) {
5785                if (hasDetachedComments(pos)) {
5786                    forEachLeadingCommentWithoutDetachedComments(cb);
5787                }
5788                else {
5789                    forEachLeadingCommentRange(currentSourceFile.text, pos, cb, /*state*/ pos);
5790                }
5791            }
5792        }
5793
5794        function forEachTrailingCommentToEmit(end: number, cb: (commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean) => void) {
5795            // Emit the trailing comments only if the container's end doesn't match because the container should take care of emitting these comments
5796            if (currentSourceFile && (containerEnd === -1 || (end !== containerEnd && end !== declarationListContainerEnd))) {
5797                forEachTrailingCommentRange(currentSourceFile.text, end, cb);
5798            }
5799        }
5800
5801        function hasDetachedComments(pos: number) {
5802            return detachedCommentsInfo !== undefined && last(detachedCommentsInfo).nodePos === pos;
5803        }
5804
5805        function forEachLeadingCommentWithoutDetachedComments(cb: (commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) => void) {
5806            if (!currentSourceFile) return;
5807            // get the leading comments from detachedPos
5808            const pos = last(detachedCommentsInfo!).detachedCommentEndPos;
5809            if (detachedCommentsInfo!.length - 1) {
5810                detachedCommentsInfo!.pop();
5811            }
5812            else {
5813                detachedCommentsInfo = undefined;
5814            }
5815
5816            forEachLeadingCommentRange(currentSourceFile.text, pos, cb, /*state*/ pos);
5817        }
5818
5819        function emitDetachedCommentsAndUpdateCommentsInfo(range: TextRange) {
5820            const currentDetachedCommentInfo = currentSourceFile && emitDetachedComments(currentSourceFile.text, getCurrentLineMap(), writer, emitComment, range, newLine, commentsDisabled);
5821            if (currentDetachedCommentInfo) {
5822                if (detachedCommentsInfo) {
5823                    detachedCommentsInfo.push(currentDetachedCommentInfo);
5824                }
5825                else {
5826                    detachedCommentsInfo = [currentDetachedCommentInfo];
5827                }
5828            }
5829        }
5830
5831        function emitComment(text: string, lineMap: number[], writer: EmitTextWriter, commentPos: number, commentEnd: number, newLine: string) {
5832            if (!currentSourceFile || !shouldWriteComment(currentSourceFile.text, commentPos)) return;
5833            emitPos(commentPos);
5834            writeCommentRange(text, lineMap, writer, commentPos, commentEnd, newLine);
5835            emitPos(commentEnd);
5836        }
5837
5838        /**
5839         * Determine if the given comment is a triple-slash
5840         *
5841         * @return true if the comment is a triple-slash comment else false
5842         */
5843        function isTripleSlashComment(commentPos: number, commentEnd: number) {
5844            return !!currentSourceFile && isRecognizedTripleSlashComment(currentSourceFile.text, commentPos, commentEnd);
5845        }
5846
5847        // Source Maps
5848
5849        function getParsedSourceMap(node: UnparsedSource) {
5850            if (node.parsedSourceMap === undefined && node.sourceMapText !== undefined) {
5851                node.parsedSourceMap = tryParseRawSourceMap(node.sourceMapText) || false;
5852            }
5853            return node.parsedSourceMap || undefined;
5854        }
5855
5856        function pipelineEmitWithSourceMaps(hint: EmitHint, node: Node) {
5857            const pipelinePhase = getNextPipelinePhase(PipelinePhase.SourceMaps, hint, node);
5858            emitSourceMapsBeforeNode(node);
5859            pipelinePhase(hint, node);
5860            emitSourceMapsAfterNode(node);
5861        }
5862
5863        function emitSourceMapsBeforeNode(node: Node) {
5864            const emitFlags = getEmitFlags(node);
5865            const sourceMapRange = getSourceMapRange(node);
5866
5867            // Emit leading sourcemap
5868            if (isUnparsedNode(node)) {
5869                Debug.assertIsDefined(node.parent, "UnparsedNodes must have parent pointers");
5870                const parsed = getParsedSourceMap(node.parent);
5871                if (parsed && sourceMapGenerator) {
5872                    sourceMapGenerator.appendSourceMap(
5873                        writer.getLine(),
5874                        writer.getColumn(),
5875                        parsed,
5876                        node.parent.sourceMapPath!,
5877                        node.parent.getLineAndCharacterOfPosition(node.pos),
5878                        node.parent.getLineAndCharacterOfPosition(node.end)
5879                    );
5880                }
5881            }
5882            else {
5883                const source = sourceMapRange.source || sourceMapSource;
5884                if (node.kind !== SyntaxKind.NotEmittedStatement
5885                    && (emitFlags & EmitFlags.NoLeadingSourceMap) === 0
5886                    && sourceMapRange.pos >= 0) {
5887                    emitSourcePos(sourceMapRange.source || sourceMapSource, skipSourceTrivia(source, sourceMapRange.pos));
5888                }
5889                if (emitFlags & EmitFlags.NoNestedSourceMaps) {
5890                    sourceMapsDisabled = true;
5891                }
5892            }
5893        }
5894
5895        function emitSourceMapsAfterNode(node: Node) {
5896            const emitFlags = getEmitFlags(node);
5897            const sourceMapRange = getSourceMapRange(node);
5898
5899            // Emit trailing sourcemap
5900            if (!isUnparsedNode(node)) {
5901                if (emitFlags & EmitFlags.NoNestedSourceMaps) {
5902                    sourceMapsDisabled = false;
5903                }
5904                if (node.kind !== SyntaxKind.NotEmittedStatement
5905                    && (emitFlags & EmitFlags.NoTrailingSourceMap) === 0
5906                    && sourceMapRange.end >= 0) {
5907                    emitSourcePos(sourceMapRange.source || sourceMapSource, sourceMapRange.end);
5908                }
5909            }
5910        }
5911
5912        /**
5913         * Skips trivia such as comments and white-space that can be optionally overridden by the source-map source
5914         */
5915        function skipSourceTrivia(source: SourceMapSource, pos: number): number {
5916            return source.skipTrivia ? source.skipTrivia(pos) : skipTrivia(source.text, pos);
5917        }
5918
5919        /**
5920         * Emits a mapping.
5921         *
5922         * If the position is synthetic (undefined or a negative value), no mapping will be
5923         * created.
5924         *
5925         * @param pos The position.
5926         */
5927        function emitPos(pos: number) {
5928            if (sourceMapsDisabled || positionIsSynthesized(pos) || isJsonSourceMapSource(sourceMapSource)) {
5929                return;
5930            }
5931
5932            const { line: sourceLine, character: sourceCharacter } = getLineAndCharacterOfPosition(sourceMapSource, pos);
5933            sourceMapGenerator!.addMapping(
5934                writer.getLine(),
5935                writer.getColumn(),
5936                sourceMapSourceIndex,
5937                sourceLine,
5938                sourceCharacter,
5939                /*nameIndex*/ undefined);
5940        }
5941
5942        function emitSourcePos(source: SourceMapSource, pos: number) {
5943            if (source !== sourceMapSource) {
5944                const savedSourceMapSource = sourceMapSource;
5945                const savedSourceMapSourceIndex = sourceMapSourceIndex;
5946                setSourceMapSource(source);
5947                emitPos(pos);
5948                resetSourceMapSource(savedSourceMapSource, savedSourceMapSourceIndex);
5949            }
5950            else {
5951                emitPos(pos);
5952            }
5953        }
5954
5955        /**
5956         * Emits a token of a node with possible leading and trailing source maps.
5957         *
5958         * @param node The node containing the token.
5959         * @param token The token to emit.
5960         * @param tokenStartPos The start pos of the token.
5961         * @param emitCallback The callback used to emit the token.
5962         */
5963        function emitTokenWithSourceMap(node: Node | undefined, token: SyntaxKind, writer: (s: string) => void, tokenPos: number, emitCallback: (token: SyntaxKind, writer: (s: string) => void, tokenStartPos: number) => number) {
5964            if (sourceMapsDisabled || node && isInJsonFile(node)) {
5965                return emitCallback(token, writer, tokenPos);
5966            }
5967
5968            const emitNode = node && node.emitNode;
5969            const emitFlags = emitNode && emitNode.flags || EmitFlags.None;
5970            const range = emitNode && emitNode.tokenSourceMapRanges && emitNode.tokenSourceMapRanges[token];
5971            const source = range && range.source || sourceMapSource;
5972
5973            tokenPos = skipSourceTrivia(source, range ? range.pos : tokenPos);
5974            if ((emitFlags & EmitFlags.NoTokenLeadingSourceMaps) === 0 && tokenPos >= 0) {
5975                emitSourcePos(source, tokenPos);
5976            }
5977
5978            tokenPos = emitCallback(token, writer, tokenPos);
5979
5980            if (range) tokenPos = range.end;
5981            if ((emitFlags & EmitFlags.NoTokenTrailingSourceMaps) === 0 && tokenPos >= 0) {
5982                emitSourcePos(source, tokenPos);
5983            }
5984
5985            return tokenPos;
5986        }
5987
5988        function setSourceMapSource(source: SourceMapSource) {
5989            if (sourceMapsDisabled) {
5990                return;
5991            }
5992
5993            sourceMapSource = source;
5994
5995            if (source === mostRecentlyAddedSourceMapSource) {
5996                // Fast path for when the new source map is the most recently added, in which case
5997                // we use its captured index without going through the source map generator.
5998                sourceMapSourceIndex = mostRecentlyAddedSourceMapSourceIndex;
5999                return;
6000            }
6001
6002            if (isJsonSourceMapSource(source)) {
6003                return;
6004            }
6005
6006            sourceMapSourceIndex = sourceMapGenerator!.addSource(source.fileName);
6007            if (printerOptions.inlineSources) {
6008                sourceMapGenerator!.setSourceContent(sourceMapSourceIndex, source.text);
6009            }
6010
6011            mostRecentlyAddedSourceMapSource = source;
6012            mostRecentlyAddedSourceMapSourceIndex = sourceMapSourceIndex;
6013        }
6014
6015        function resetSourceMapSource(source: SourceMapSource, sourceIndex: number) {
6016            sourceMapSource = source;
6017            sourceMapSourceIndex = sourceIndex;
6018        }
6019
6020        function isJsonSourceMapSource(sourceFile: SourceMapSource) {
6021            return fileExtensionIs(sourceFile.fileName, Extension.Json);
6022        }
6023    }
6024
6025    function createBracketsMap() {
6026        const brackets: string[][] = [];
6027        brackets[ListFormat.Braces] = ["{", "}"];
6028        brackets[ListFormat.Parenthesis] = ["(", ")"];
6029        brackets[ListFormat.AngleBrackets] = ["<", ">"];
6030        brackets[ListFormat.SquareBrackets] = ["[", "]"];
6031        return brackets;
6032    }
6033
6034    function getOpeningBracket(format: ListFormat) {
6035        return brackets[format & ListFormat.BracketsMask][0];
6036    }
6037
6038    function getClosingBracket(format: ListFormat) {
6039        return brackets[format & ListFormat.BracketsMask][1];
6040    }
6041
6042    // Flags enum to track count of temp variables and a few dedicated names
6043    const enum TempFlags {
6044        Auto = 0x00000000,  // No preferred name
6045        CountMask = 0x0FFFFFFF,  // Temp variable counter
6046        _i = 0x10000000,  // Use/preference flag for '_i'
6047    }
6048
6049    interface OrdinalParentheizerRuleSelector<T extends Node> {
6050        select(index: number): ((node: T) => T) | undefined;
6051    }
6052
6053    type ParenthesizerRule<T extends Node> = (node: T) => T;
6054
6055    type ParenthesizerRuleOrSelector<T extends Node> = OrdinalParentheizerRuleSelector<T> | ParenthesizerRule<T>;
6056
6057    function emitListItemNoParenthesizer(node: Node, emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, _parenthesizerRule: ParenthesizerRuleOrSelector<Node> | undefined, _index: number) {
6058        emit(node);
6059    }
6060
6061    function emitListItemWithParenthesizerRuleSelector(node: Node, emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parenthesizerRuleSelector: OrdinalParentheizerRuleSelector<Node>, index: number) {
6062        emit(node, parenthesizerRuleSelector.select(index));
6063    }
6064
6065    function emitListItemWithParenthesizerRule(node: Node, emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parenthesizerRule: ParenthesizerRule<Node> | undefined, _index: number) {
6066        emit(node, parenthesizerRule);
6067    }
6068
6069    function getEmitListItem<T extends Node, R extends ParenthesizerRuleOrSelector<T> | undefined>(emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parenthesizerRule: R): (node: Node, emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parenthesizerRule: R, index: number) => void {
6070        return emit.length === 1 ? emitListItemNoParenthesizer :
6071            typeof parenthesizerRule === "object" ? emitListItemWithParenthesizerRuleSelector :
6072            emitListItemWithParenthesizerRule;
6073    }
6074}
6075