• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*@internal*/
2namespace ts {
3    export function getFileEmitOutput(program: Program, sourceFile: SourceFile, emitOnlyDtsFiles: boolean,
4        cancellationToken?: CancellationToken, customTransformers?: CustomTransformers, forceDtsEmit?: boolean): EmitOutput {
5        const outputFiles: OutputFile[] = [];
6        const { emitSkipped, diagnostics, exportedModulesFromDeclarationEmit } = program.emit(sourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers, forceDtsEmit);
7        return { outputFiles, emitSkipped, diagnostics, exportedModulesFromDeclarationEmit };
8
9        function writeFile(fileName: string, text: string, writeByteOrderMark: boolean) {
10            outputFiles.push({ name: fileName, writeByteOrderMark, text });
11        }
12    }
13
14    export interface ReusableBuilderState {
15        /**
16         * Information of the file eg. its version, signature etc
17         */
18        fileInfos: ReadonlyESMap<Path, BuilderState.FileInfo>;
19        /**
20         * Contains the map of ReferencedSet=Referenced files of the file if module emit is enabled
21         * Otherwise undefined
22         * Thus non undefined value indicates, module emit
23         */
24        readonly referencedMap?: ReadonlyESMap<Path, BuilderState.ReferencedSet> | undefined;
25        /**
26         * Contains the map of exported modules ReferencedSet=exported module files from the file if module emit is enabled
27         * Otherwise undefined
28         */
29        readonly exportedModulesMap?: ReadonlyESMap<Path, BuilderState.ReferencedSet> | undefined;
30    }
31
32    export interface BuilderState {
33        /**
34         * Information of the file eg. its version, signature etc
35         */
36        fileInfos: ESMap<Path, BuilderState.FileInfo>;
37        /**
38         * Contains the map of ReferencedSet=Referenced files of the file if module emit is enabled
39         * Otherwise undefined
40         * Thus non undefined value indicates, module emit
41         */
42        readonly referencedMap: ReadonlyESMap<Path, BuilderState.ReferencedSet> | undefined;
43        /**
44         * Contains the map of exported modules ReferencedSet=exported module files from the file if module emit is enabled
45         * Otherwise undefined
46         */
47        readonly exportedModulesMap: ESMap<Path, BuilderState.ReferencedSet> | undefined;
48        /**
49         * Map of files that have already called update signature.
50         * That means hence forth these files are assumed to have
51         * no change in their signature for this version of the program
52         */
53        hasCalledUpdateShapeSignature: Set<Path>;
54        /**
55         * Cache of all files excluding default library file for the current program
56         */
57        allFilesExcludingDefaultLibraryFile?: readonly SourceFile[];
58        /**
59         * Cache of all the file names
60         */
61        allFileNames?: readonly string[];
62    }
63
64    export namespace BuilderState {
65        /**
66         * Information about the source file: Its version and optional signature from last emit
67         */
68        export interface FileInfo {
69            readonly version: string;
70            signature: string | undefined;
71            affectsGlobalScope: boolean;
72        }
73        /**
74         * Referenced files with values for the keys as referenced file's path to be true
75         */
76        export type ReferencedSet = ReadonlySet<Path>;
77        /**
78         * Compute the hash to store the shape of the file
79         */
80        export type ComputeHash = ((data: string) => string) | undefined;
81
82        /**
83         * Exported modules to from declaration emit being computed.
84         * This can contain false in the affected file path to specify that there are no exported module(types from other modules) for this file
85         */
86        export type ComputingExportedModulesMap = ESMap<Path, ReferencedSet | false>;
87
88        /**
89         * Get the referencedFile from the imported module symbol
90         */
91        function getReferencedFileFromImportedModuleSymbol(symbol: Symbol) {
92            if (symbol.declarations && symbol.declarations[0]) {
93                const declarationSourceFile = getSourceFileOfNode(symbol.declarations[0]);
94                return declarationSourceFile && declarationSourceFile.resolvedPath;
95            }
96        }
97
98        /**
99         * Get the referencedFile from the import name node from file
100         */
101        function getReferencedFileFromImportLiteral(checker: TypeChecker, importName: StringLiteralLike) {
102            const symbol = checker.getSymbolAtLocation(importName);
103            return symbol && getReferencedFileFromImportedModuleSymbol(symbol);
104        }
105
106        /**
107         * Gets the path to reference file from file name, it could be resolvedPath if present otherwise path
108         */
109        function getReferencedFileFromFileName(program: Program, fileName: string, sourceFileDirectory: Path, getCanonicalFileName: GetCanonicalFileName): Path {
110            return toPath(program.getProjectReferenceRedirect(fileName) || fileName, sourceFileDirectory, getCanonicalFileName);
111        }
112
113        /**
114         * Gets the referenced files for a file from the program with values for the keys as referenced file's path to be true
115         */
116        function getReferencedFiles(program: Program, sourceFile: SourceFile, getCanonicalFileName: GetCanonicalFileName): Set<Path> | undefined {
117            let referencedFiles: Set<Path> | undefined;
118
119            // We need to use a set here since the code can contain the same import twice,
120            // but that will only be one dependency.
121            // To avoid invernal conversion, the key of the referencedFiles map must be of type Path
122            if (sourceFile.imports && sourceFile.imports.length > 0) {
123                const checker: TypeChecker = program.getTypeChecker();
124                for (const importName of sourceFile.imports) {
125                    const declarationSourceFilePath = getReferencedFileFromImportLiteral(checker, importName);
126                    if (declarationSourceFilePath) {
127                        addReferencedFile(declarationSourceFilePath);
128                    }
129                }
130            }
131
132            const sourceFileDirectory = getDirectoryPath(sourceFile.resolvedPath);
133            // Handle triple slash references
134            if (sourceFile.referencedFiles && sourceFile.referencedFiles.length > 0) {
135                for (const referencedFile of sourceFile.referencedFiles) {
136                    const referencedPath = getReferencedFileFromFileName(program, referencedFile.fileName, sourceFileDirectory, getCanonicalFileName);
137                    addReferencedFile(referencedPath);
138                }
139            }
140
141            // Handle type reference directives
142            if (sourceFile.resolvedTypeReferenceDirectiveNames) {
143                sourceFile.resolvedTypeReferenceDirectiveNames.forEach((resolvedTypeReferenceDirective) => {
144                    if (!resolvedTypeReferenceDirective) {
145                        return;
146                    }
147
148                    const fileName = resolvedTypeReferenceDirective.resolvedFileName!; // TODO: GH#18217
149                    const typeFilePath = getReferencedFileFromFileName(program, fileName, sourceFileDirectory, getCanonicalFileName);
150                    addReferencedFile(typeFilePath);
151                });
152            }
153
154            // Add module augmentation as references
155            if (sourceFile.moduleAugmentations.length) {
156                const checker = program.getTypeChecker();
157                for (const moduleName of sourceFile.moduleAugmentations) {
158                    if (!isStringLiteral(moduleName)) { continue; }
159                    const symbol = checker.getSymbolAtLocation(moduleName);
160                    if (!symbol) { continue; }
161
162                    // Add any file other than our own as reference
163                    addReferenceFromAmbientModule(symbol);
164                }
165            }
166
167            // From ambient modules
168            for (const ambientModule of program.getTypeChecker().getAmbientModules()) {
169                if (ambientModule.declarations.length > 1) {
170                    addReferenceFromAmbientModule(ambientModule);
171                }
172            }
173
174            return referencedFiles;
175
176            function addReferenceFromAmbientModule(symbol: Symbol) {
177                // Add any file other than our own as reference
178                for (const declaration of symbol.declarations) {
179                    const declarationSourceFile = getSourceFileOfNode(declaration);
180                    if (declarationSourceFile &&
181                        declarationSourceFile !== sourceFile) {
182                        addReferencedFile(declarationSourceFile.resolvedPath);
183                    }
184                }
185            }
186
187            function addReferencedFile(referencedPath: Path) {
188                (referencedFiles || (referencedFiles = new Set())).add(referencedPath);
189            }
190        }
191
192        /**
193         * Returns true if oldState is reusable, that is the emitKind = module/non module has not changed
194         */
195        export function canReuseOldState(newReferencedMap: ReadonlyESMap<Path, ReferencedSet> | undefined, oldState: Readonly<ReusableBuilderState> | undefined) {
196            return oldState && !oldState.referencedMap === !newReferencedMap;
197        }
198
199        /**
200         * Creates the state of file references and signature for the new program from oldState if it is safe
201         */
202        export function create(newProgram: Program, getCanonicalFileName: GetCanonicalFileName, oldState?: Readonly<ReusableBuilderState>): BuilderState {
203            const fileInfos = new Map<Path, FileInfo>();
204            const referencedMap = newProgram.getCompilerOptions().module !== ModuleKind.None ? new Map<Path, ReferencedSet>() : undefined;
205            const exportedModulesMap = referencedMap ? new Map<Path, ReferencedSet>() : undefined;
206            const hasCalledUpdateShapeSignature = new Set<Path>();
207            const useOldState = canReuseOldState(referencedMap, oldState);
208
209            // Ensure source files have parent pointers set
210            newProgram.getTypeChecker();
211
212            // Create the reference map, and set the file infos
213            for (const sourceFile of newProgram.getSourceFiles()) {
214                const version = Debug.checkDefined(sourceFile.version, "Program intended to be used with Builder should have source files with versions set");
215                const oldInfo = useOldState ? oldState!.fileInfos.get(sourceFile.resolvedPath) : undefined;
216                if (referencedMap) {
217                    const newReferences = getReferencedFiles(newProgram, sourceFile, getCanonicalFileName);
218                    if (newReferences) {
219                        referencedMap.set(sourceFile.resolvedPath, newReferences);
220                    }
221                    // Copy old visible to outside files map
222                    if (useOldState) {
223                        const exportedModules = oldState!.exportedModulesMap!.get(sourceFile.resolvedPath);
224                        if (exportedModules) {
225                            exportedModulesMap!.set(sourceFile.resolvedPath, exportedModules);
226                        }
227                    }
228                }
229                fileInfos.set(sourceFile.resolvedPath, { version, signature: oldInfo && oldInfo.signature, affectsGlobalScope: isFileAffectingGlobalScope(sourceFile) });
230            }
231
232            return {
233                fileInfos,
234                referencedMap,
235                exportedModulesMap,
236                hasCalledUpdateShapeSignature
237            };
238        }
239
240        /**
241         * Releases needed properties
242         */
243        export function releaseCache(state: BuilderState) {
244            state.allFilesExcludingDefaultLibraryFile = undefined;
245            state.allFileNames = undefined;
246        }
247
248        /**
249         * Creates a clone of the state
250         */
251        export function clone(state: Readonly<BuilderState>): BuilderState {
252            // Dont need to backup allFiles info since its cache anyway
253            return {
254                fileInfos: new Map(state.fileInfos),
255                referencedMap: state.referencedMap && new Map(state.referencedMap),
256                exportedModulesMap: state.exportedModulesMap && new Map(state.exportedModulesMap),
257                hasCalledUpdateShapeSignature: new Set(state.hasCalledUpdateShapeSignature),
258            };
259        }
260
261        /**
262         * Gets the files affected by the path from the program
263         */
264        export function getFilesAffectedBy(state: BuilderState, programOfThisState: Program, path: Path, cancellationToken: CancellationToken | undefined, computeHash: ComputeHash, cacheToUpdateSignature?: ESMap<Path, string>, exportedModulesMapCache?: ComputingExportedModulesMap): readonly SourceFile[] {
265            // Since the operation could be cancelled, the signatures are always stored in the cache
266            // They will be committed once it is safe to use them
267            // eg when calling this api from tsserver, if there is no cancellation of the operation
268            // In the other cases the affected files signatures are committed only after the iteration through the result is complete
269            const signatureCache = cacheToUpdateSignature || new Map();
270            const sourceFile = programOfThisState.getSourceFileByPath(path);
271            if (!sourceFile) {
272                return emptyArray;
273            }
274
275            if (!updateShapeSignature(state, programOfThisState, sourceFile, signatureCache, cancellationToken, computeHash, exportedModulesMapCache)) {
276                return [sourceFile];
277            }
278
279            const result = (state.referencedMap ? getFilesAffectedByUpdatedShapeWhenModuleEmit : getFilesAffectedByUpdatedShapeWhenNonModuleEmit)(state, programOfThisState, sourceFile, signatureCache, cancellationToken, computeHash, exportedModulesMapCache);
280            if (!cacheToUpdateSignature) {
281                // Commit all the signatures in the signature cache
282                updateSignaturesFromCache(state, signatureCache);
283            }
284            return result;
285        }
286
287        /**
288         * Updates the signatures from the cache into state's fileinfo signatures
289         * This should be called whenever it is safe to commit the state of the builder
290         */
291        export function updateSignaturesFromCache(state: BuilderState, signatureCache: ESMap<Path, string>) {
292            signatureCache.forEach((signature, path) => updateSignatureOfFile(state, signature, path));
293        }
294
295        export function updateSignatureOfFile(state: BuilderState, signature: string | undefined, path: Path) {
296            state.fileInfos.get(path)!.signature = signature;
297            state.hasCalledUpdateShapeSignature.add(path);
298        }
299
300        /**
301         * Returns if the shape of the signature has changed since last emit
302         */
303        export function updateShapeSignature(state: Readonly<BuilderState>, programOfThisState: Program, sourceFile: SourceFile, cacheToUpdateSignature: ESMap<Path, string>, cancellationToken: CancellationToken | undefined, computeHash: ComputeHash, exportedModulesMapCache?: ComputingExportedModulesMap) {
304            Debug.assert(!!sourceFile);
305            Debug.assert(!exportedModulesMapCache || !!state.exportedModulesMap, "Compute visible to outside map only if visibleToOutsideReferencedMap present in the state");
306
307            // If we have cached the result for this file, that means hence forth we should assume file shape is uptodate
308            if (state.hasCalledUpdateShapeSignature.has(sourceFile.resolvedPath) || cacheToUpdateSignature.has(sourceFile.resolvedPath)) {
309                return false;
310            }
311
312            const info = state.fileInfos.get(sourceFile.resolvedPath);
313            if (!info) return Debug.fail();
314
315            const prevSignature = info.signature;
316            let latestSignature: string;
317            if (sourceFile.isDeclarationFile) {
318                latestSignature = sourceFile.version;
319                if (exportedModulesMapCache && latestSignature !== prevSignature) {
320                    // All the references in this file are exported
321                    const references = state.referencedMap ? state.referencedMap.get(sourceFile.resolvedPath) : undefined;
322                    exportedModulesMapCache.set(sourceFile.resolvedPath, references || false);
323                }
324            }
325            else {
326                const emitOutput = getFileEmitOutput(
327                    programOfThisState,
328                    sourceFile,
329                    /*emitOnlyDtsFiles*/ true,
330                    cancellationToken,
331                    /*customTransformers*/ undefined,
332                    /*forceDtsEmit*/ true
333                );
334                const firstDts = emitOutput.outputFiles &&
335                    programOfThisState.getCompilerOptions().declarationMap ?
336                    emitOutput.outputFiles.length > 1 ? emitOutput.outputFiles[1] : undefined :
337                    emitOutput.outputFiles.length > 0 ? emitOutput.outputFiles[0] : undefined;
338                if (firstDts) {
339                    Debug.assert(isDeclarationFileName(firstDts.name), "File extension for signature expected to be dts or dets", () => `Found: ${getAnyExtensionFromPath(firstDts.name)} for ${firstDts.name}:: All output files: ${JSON.stringify(emitOutput.outputFiles.map(f => f.name))}`);
340                    latestSignature = (computeHash || generateDjb2Hash)(firstDts.text);
341                    if (exportedModulesMapCache && latestSignature !== prevSignature) {
342                        updateExportedModules(sourceFile, emitOutput.exportedModulesFromDeclarationEmit, exportedModulesMapCache);
343                    }
344                }
345                else {
346                    latestSignature = prevSignature!; // TODO: GH#18217
347                }
348
349            }
350            cacheToUpdateSignature.set(sourceFile.resolvedPath, latestSignature);
351
352            return !prevSignature || latestSignature !== prevSignature;
353        }
354
355        /**
356         * Coverts the declaration emit result into exported modules map
357         */
358        function updateExportedModules(sourceFile: SourceFile, exportedModulesFromDeclarationEmit: ExportedModulesFromDeclarationEmit | undefined, exportedModulesMapCache: ComputingExportedModulesMap) {
359            if (!exportedModulesFromDeclarationEmit) {
360                exportedModulesMapCache.set(sourceFile.resolvedPath, false);
361                return;
362            }
363
364            let exportedModules: Set<Path> | undefined;
365            exportedModulesFromDeclarationEmit.forEach(symbol => addExportedModule(getReferencedFileFromImportedModuleSymbol(symbol)));
366            exportedModulesMapCache.set(sourceFile.resolvedPath, exportedModules || false);
367
368            function addExportedModule(exportedModulePath: Path | undefined) {
369                if (exportedModulePath) {
370                    if (!exportedModules) {
371                        exportedModules = new Set();
372                    }
373                    exportedModules.add(exportedModulePath);
374                }
375            }
376        }
377
378        /**
379         * Updates the exported modules from cache into state's exported modules map
380         * This should be called whenever it is safe to commit the state of the builder
381         */
382        export function updateExportedFilesMapFromCache(state: BuilderState, exportedModulesMapCache: ComputingExportedModulesMap | undefined) {
383            if (exportedModulesMapCache) {
384                Debug.assert(!!state.exportedModulesMap);
385                exportedModulesMapCache.forEach((exportedModules, path) => {
386                    if (exportedModules) {
387                        state.exportedModulesMap!.set(path, exportedModules);
388                    }
389                    else {
390                        state.exportedModulesMap!.delete(path);
391                    }
392                });
393            }
394        }
395
396        /**
397         * Get all the dependencies of the sourceFile
398         */
399        export function getAllDependencies(state: BuilderState, programOfThisState: Program, sourceFile: SourceFile): readonly string[] {
400            const compilerOptions = programOfThisState.getCompilerOptions();
401            // With --out or --outFile all outputs go into single file, all files depend on each other
402            if (outFile(compilerOptions)) {
403                return getAllFileNames(state, programOfThisState);
404            }
405
406            // If this is non module emit, or its a global file, it depends on all the source files
407            if (!state.referencedMap || isFileAffectingGlobalScope(sourceFile)) {
408                return getAllFileNames(state, programOfThisState);
409            }
410
411            // Get the references, traversing deep from the referenceMap
412            const seenMap = new Set<Path>();
413            const queue = [sourceFile.resolvedPath];
414            while (queue.length) {
415                const path = queue.pop()!;
416                if (!seenMap.has(path)) {
417                    seenMap.add(path);
418                    const references = state.referencedMap.get(path);
419                    if (references) {
420                        const iterator = references.keys();
421                        for (let iterResult = iterator.next(); !iterResult.done; iterResult = iterator.next()) {
422                            queue.push(iterResult.value);
423                        }
424                    }
425                }
426            }
427
428            return arrayFrom(mapDefinedIterator(seenMap.keys(), path => programOfThisState.getSourceFileByPath(path)?.fileName ?? path));
429        }
430
431        /**
432         * Gets the names of all files from the program
433         */
434        function getAllFileNames(state: BuilderState, programOfThisState: Program): readonly string[] {
435            if (!state.allFileNames) {
436                const sourceFiles = programOfThisState.getSourceFiles();
437                state.allFileNames = sourceFiles === emptyArray ? emptyArray : sourceFiles.map(file => file.fileName);
438            }
439            return state.allFileNames;
440        }
441
442        /**
443         * Gets the files referenced by the the file path
444         */
445        export function getReferencedByPaths(state: Readonly<BuilderState>, referencedFilePath: Path) {
446            return arrayFrom(mapDefinedIterator(state.referencedMap!.entries(), ([filePath, referencesInFile]) =>
447                referencesInFile.has(referencedFilePath) ? filePath : undefined
448            ));
449        }
450
451        /**
452         * For script files that contains only ambient external modules, although they are not actually external module files,
453         * they can only be consumed via importing elements from them. Regular script files cannot consume them. Therefore,
454         * there are no point to rebuild all script files if these special files have changed. However, if any statement
455         * in the file is not ambient external module, we treat it as a regular script file.
456         */
457        function containsOnlyAmbientModules(sourceFile: SourceFile) {
458            for (const statement of sourceFile.statements) {
459                if (!isModuleWithStringLiteralName(statement)) {
460                    return false;
461                }
462            }
463            return true;
464        }
465
466        /**
467         * Return true if file contains anything that augments to global scope we need to build them as if
468         * they are global files as well as module
469         */
470        function containsGlobalScopeAugmentation(sourceFile: SourceFile) {
471            return some(sourceFile.moduleAugmentations, augmentation => isGlobalScopeAugmentation(augmentation.parent as ModuleDeclaration));
472        }
473
474        /**
475         * Return true if the file will invalidate all files because it affectes global scope
476         */
477        function isFileAffectingGlobalScope(sourceFile: SourceFile) {
478            return containsGlobalScopeAugmentation(sourceFile) ||
479                !isExternalModule(sourceFile) && !containsOnlyAmbientModules(sourceFile);
480        }
481
482        /**
483         * Gets all files of the program excluding the default library file
484         */
485        export function getAllFilesExcludingDefaultLibraryFile(state: BuilderState, programOfThisState: Program, firstSourceFile: SourceFile | undefined): readonly SourceFile[] {
486            // Use cached result
487            if (state.allFilesExcludingDefaultLibraryFile) {
488                return state.allFilesExcludingDefaultLibraryFile;
489            }
490
491            let result: SourceFile[] | undefined;
492            if (firstSourceFile) addSourceFile(firstSourceFile);
493            for (const sourceFile of programOfThisState.getSourceFiles()) {
494                if (sourceFile !== firstSourceFile) {
495                    addSourceFile(sourceFile);
496                }
497            }
498            state.allFilesExcludingDefaultLibraryFile = result || emptyArray;
499            return state.allFilesExcludingDefaultLibraryFile;
500
501            function addSourceFile(sourceFile: SourceFile) {
502                if (!programOfThisState.isSourceFileDefaultLibrary(sourceFile)) {
503                    (result || (result = [])).push(sourceFile);
504                }
505            }
506        }
507
508        /**
509         * When program emits non modular code, gets the files affected by the sourceFile whose shape has changed
510         */
511        function getFilesAffectedByUpdatedShapeWhenNonModuleEmit(state: BuilderState, programOfThisState: Program, sourceFileWithUpdatedShape: SourceFile) {
512            const compilerOptions = programOfThisState.getCompilerOptions();
513            // If `--out` or `--outFile` is specified, any new emit will result in re-emitting the entire project,
514            // so returning the file itself is good enough.
515            if (compilerOptions && outFile(compilerOptions)) {
516                return [sourceFileWithUpdatedShape];
517            }
518            return getAllFilesExcludingDefaultLibraryFile(state, programOfThisState, sourceFileWithUpdatedShape);
519        }
520
521        /**
522         * When program emits modular code, gets the files affected by the sourceFile whose shape has changed
523         */
524        function getFilesAffectedByUpdatedShapeWhenModuleEmit(state: BuilderState, programOfThisState: Program, sourceFileWithUpdatedShape: SourceFile, cacheToUpdateSignature: ESMap<Path, string>, cancellationToken: CancellationToken | undefined, computeHash: ComputeHash, exportedModulesMapCache: ComputingExportedModulesMap | undefined) {
525            if (isFileAffectingGlobalScope(sourceFileWithUpdatedShape)) {
526                return getAllFilesExcludingDefaultLibraryFile(state, programOfThisState, sourceFileWithUpdatedShape);
527            }
528
529            const compilerOptions = programOfThisState.getCompilerOptions();
530            if (compilerOptions && (compilerOptions.isolatedModules || outFile(compilerOptions))) {
531                return [sourceFileWithUpdatedShape];
532            }
533
534            // Now we need to if each file in the referencedBy list has a shape change as well.
535            // Because if so, its own referencedBy files need to be saved as well to make the
536            // emitting result consistent with files on disk.
537            const seenFileNamesMap = new Map<Path, SourceFile>();
538
539            // Start with the paths this file was referenced by
540            seenFileNamesMap.set(sourceFileWithUpdatedShape.resolvedPath, sourceFileWithUpdatedShape);
541            const queue = getReferencedByPaths(state, sourceFileWithUpdatedShape.resolvedPath);
542            while (queue.length > 0) {
543                const currentPath = queue.pop()!;
544                if (!seenFileNamesMap.has(currentPath)) {
545                    const currentSourceFile = programOfThisState.getSourceFileByPath(currentPath)!;
546                    seenFileNamesMap.set(currentPath, currentSourceFile);
547                    if (currentSourceFile && updateShapeSignature(state, programOfThisState, currentSourceFile, cacheToUpdateSignature, cancellationToken, computeHash, exportedModulesMapCache)) {
548                        queue.push(...getReferencedByPaths(state, currentSourceFile.resolvedPath));
549                    }
550                }
551            }
552
553            // Return array of values that needs emit
554            return arrayFrom(mapDefinedIterator(seenFileNamesMap.values(), value => value));
555        }
556    }
557}
558