Changed implementation to use closure

This commit is contained in:
Bill Ticehurst
2016-06-21 13:42:02 -07:00
parent 4d4f679ec4
commit 07bfbab6ff
3 changed files with 33 additions and 47 deletions

View File

@@ -1066,6 +1066,16 @@ namespace ts {
let resolvedTypeReferenceDirectives: Map<ResolvedTypeReferenceDirective> = {};
let fileProcessingDiagnostics = createDiagnosticCollection();
// The below settings are to track if a .js file should be add to the program if loaded via searching under node_modules.
// This works as imported modules are discovered recursively in a depth first manner, specifically:
// - For each root file, findSourceFile is called.
// - This calls processImportedModules for each module imported in the source file.
// - This calls resolveModuleNames, and then calls findSourceFile for each resolved module.
// As all these operations happen - and are nested - within the createProgram call, they close over the below variables.
// The current resolution depth is tracked by incrementing/decrementing as the depth first search progresses.
const maxNodeModulesJsDepth = options.maxNodeModuleJsDepth || 2;
let currentNodeModulesJsDepth = 0;
const start = new Date().getTime();
host = host || createCompilerHost(options);
@@ -1869,7 +1879,7 @@ namespace ts {
}
// Get source file from normalized fileName
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, isReference: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number, isFileFromNodeSearch?: boolean): SourceFile {
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, isReference: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): SourceFile {
if (filesByName.contains(path)) {
const file = filesByName.get(path);
// try to check if we've already seen this file but with a different casing in path
@@ -1878,12 +1888,6 @@ namespace ts {
reportFileNamesDifferOnlyInCasingError(fileName, file.fileName, refFile, refPos, refEnd);
}
// If this was a file found by a node_modules search, set the nodeModuleSearchDistance to parent distance + 1.
if (isFileFromNodeSearch) {
const newDistance = (refFile && refFile.nodeModuleSearchDistance) === undefined ? 1 : refFile.nodeModuleSearchDistance + 1;
// If already set on the file, don't overwrite if it was already found closer (which may be '0' if added as a root file)
file.nodeModuleSearchDistance = (typeof file.nodeModuleSearchDistance === "number") ? Math.min(file.nodeModuleSearchDistance, newDistance) : newDistance;
}
return file;
}
@@ -1902,12 +1906,6 @@ namespace ts {
if (file) {
file.path = path;
// Default to same distance as parent. Add one if found by a search.
file.nodeModuleSearchDistance = (refFile && refFile.nodeModuleSearchDistance) || 0;
if (isFileFromNodeSearch) {
file.nodeModuleSearchDistance++;
}
if (host.useCaseSensitiveFileNames()) {
// for case-sensitive file systems check if we've already seen some file with similar filename ignoring case
const existingFile = filesByNameIgnoreCase.get(path);
@@ -2020,13 +2018,11 @@ namespace ts {
}
function processImportedModules(file: SourceFile, basePath: string) {
const maxJsNodeModuleSearchDistance = options.maxNodeModuleJsDepth || 0;
collectExternalModuleReferences(file);
if (file.imports.length || file.moduleAugmentations.length) {
file.resolvedModules = {};
const moduleNames = map(concatenate(file.imports, file.moduleAugmentations), getTextOfLiteral);
const resolutions = resolveModuleNamesWorker(moduleNames, getNormalizedAbsolutePath(file.fileName, currentDirectory));
file.nodeModuleSearchDistance = file.nodeModuleSearchDistance || 0;
for (let i = 0; i < moduleNames.length; i++) {
const resolution = resolutions[i];
setResolvedModule(file, moduleNames[i], resolution);
@@ -2035,32 +2031,24 @@ namespace ts {
// - noResolve is falsy
// - module name comes from the list of imports
// - it's not a top level JavaScript module that exceeded the search max
const exceedsJsSearchDepth = resolution && resolution.isExternalLibraryImport &&
hasJavaScriptFileExtension(resolution.resolvedFileName) &&
file.nodeModuleSearchDistance >= maxJsNodeModuleSearchDistance;
const shouldAddFile = resolution && !options.noResolve && i < file.imports.length && !exceedsJsSearchDepth;
let isJsFileUnderNodeModules = resolution && resolution.isExternalLibraryImport &&
hasJavaScriptFileExtension(resolution.resolvedFileName);
if (isJsFileUnderNodeModules) {
currentNodeModulesJsDepth++;
}
const shouldAddFile = resolution && !options.noResolve && i < file.imports.length &&
!(isJsFileUnderNodeModules && currentNodeModulesJsDepth > maxNodeModulesJsDepth);
if (shouldAddFile) {
// const importedFile = findSourceFile(resolution.resolvedFileName,
// toPath(resolution.resolvedFileName, currentDirectory, getCanonicalFileName),
// /*isDefaultLib*/ false, /*isReference*/ false,
// file,
// skipTrivia(file.text, file.imports[i].pos),
// file.imports[i].end,
// resolution.isExternalLibraryImport);
//
// // TODO (billti): Should we check here if a JavaScript file is a CommonJS file, or doesn't have /// references?
// if (importedFile && resolution.isExternalLibraryImport && !hasJavaScriptFileExtension(importedFile.fileName)) {
// if (!isExternalModule(importedFile) && importedFile.statements.length) {
// const start = getTokenPosOfNode(file.imports[i], file);
// fileProcessingDiagnostics.add(createFileDiagnostic(file, start, file.imports[i].end - start, Diagnostics.Exported_external_package_typings_file_0_is_not_a_module_Please_contact_the_package_author_to_update_the_package_definition, importedFile.fileName));
// }
// else if (importedFile.referencedFiles.length) {
// const firstRef = importedFile.referencedFiles[0];
// fileProcessingDiagnostics.add(createFileDiagnostic(importedFile, firstRef.pos, firstRef.end - firstRef.pos, Diagnostics.Exported_external_package_typings_file_cannot_contain_tripleslash_references_Please_contact_the_package_author_to_update_the_package_definition));
// }
// }
findSourceFile(resolution.resolvedFileName, toPath(resolution.resolvedFileName, currentDirectory, getCanonicalFileName), /*isDefaultLib*/ false, /*isReference*/ false, file, skipTrivia(file.text, file.imports[i].pos), file.imports[i].end);
findSourceFile(resolution.resolvedFileName,
toPath(resolution.resolvedFileName, currentDirectory, getCanonicalFileName),
/*isDefaultLib*/ false, /*isReference*/ false,
file,
skipTrivia(file.text, file.imports[i].pos),
file.imports[i].end);
}
if (isJsFileUnderNodeModules) {
currentNodeModulesJsDepth--;
}
}
}

View File

@@ -1642,8 +1642,6 @@ namespace ts {
/* @internal */ externalModuleIndicator: Node;
// The first node that causes this file to be a CommonJS module
/* @internal */ commonJsModuleIndicator: Node;
// The number of times node_modules was searched to locate the package containing this file
/* @internal */ nodeModuleSearchDistance?: number;
/* @internal */ identifiers: Map<string>;
/* @internal */ nodeCount: number;

View File

@@ -2275,8 +2275,8 @@ namespace ts {
else {
const sourceFiles = targetSourceFile === undefined ? host.getSourceFiles() : [targetSourceFile];
for (const sourceFile of sourceFiles) {
// Don't emit if source file is a declaration file, or was found by a search under 'node_modules'
if (!isDeclarationFile(sourceFile) && !sourceFile.nodeModuleSearchDistance) {
// Don't emit if source file is a declaration file, or TODO: was found by a search under 'node_modules'
if (!isDeclarationFile(sourceFile)) {
onSingleFileEmit(host, sourceFile);
}
}
@@ -2310,10 +2310,10 @@ namespace ts {
function onBundledEmit(host: EmitHost) {
// Can emit only sources that are not declaration file and are either non module code or module with --module or --target es6 specified
const bundledSources = filter(host.getSourceFiles(),
sourceFile => !isDeclarationFile(sourceFile) && // Not a declaration file
!sourceFile.nodeModuleSearchDistance && // Not loaded from searching under node_modules
(!isExternalModule(sourceFile) || // non module file
(getEmitModuleKind(options) && isExternalModule(sourceFile)))); // module that can emit - note falsy value from getEmitModuleKind means the module kind that shouldn't be emitted
// TODO: Don't emit from source resolved by searching under node_modules
sourceFile => !isDeclarationFile(sourceFile) && // Not a declaration file
(!isExternalModule(sourceFile) || // non module file
!!getEmitModuleKind(options))); // module that can emit - note falsy value from getEmitModuleKind means the module kind that shouldn't be emitted
if (bundledSources.length) {
const jsFilePath = options.outFile || options.out;
const emitFileNames: EmitFileNames = {