From 62370a0d08a6c20c2250d0f808fbfaec4c12a663 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Wed, 25 Nov 2015 16:41:09 -0800 Subject: [PATCH] addressed PR feedback --- src/compiler/commandLineParser.ts | 34 +++++++++++++++++-- src/compiler/core.ts | 5 ++- src/compiler/diagnosticMessages.json | 13 ++++++- src/compiler/program.ts | 34 ++++++++++++++----- src/harness/harness.ts | 3 ++ .../pathMappingBasedModuleResolution10_2.ts | 4 +-- tests/cases/unittests/moduleResolution.ts | 4 +-- 7 files changed, 80 insertions(+), 17 deletions(-) diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 249e2f30c29..6ed27aeb3bf 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -300,7 +300,8 @@ namespace ts { // use type = object to copy the value as-is name: "rootDirs", type: "object", - isTSConfigOnly: true + isTSConfigOnly: true, + isFilePath: true }, { name: "traceModuleResolution", @@ -595,7 +596,36 @@ namespace ts { } } if (opt.isFilePath) { - value = normalizePath(combinePaths(basePath, value)); + switch (typeof value) { + case "string": + value = normalizePath(combinePaths(basePath, value)); + break; + case "object": + // "object" options with 'isFilePath' = true expected to be string arrays + let paths: string[] = []; + let invalidOptionType = false; + if (!isArray(value)) { + invalidOptionType = true; + } + else { + for (const element of value) { + if (typeof element === "string") { + paths.push(normalizePath(combinePaths(basePath, element))); + } + else { + invalidOptionType = true; + break; + } + } + } + if (invalidOptionType) { + errors.push(createCompilerDiagnostic(Diagnostics.Option_0_should_have_array_of_strings_as_a_value, opt.name)); + } + else { + value = paths; + } + break; + } if (value === "") { value = "."; } diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 50b10ac5a90..df6158b9887 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -74,7 +74,10 @@ namespace ts { GreaterThan = 1 } - export interface StringSet extends Map { } + /* @internal */ + export function isArray(obj: any): boolean { + return Array.isArray ? Array.isArray(obj) : typeof obj === "object" && obj instanceof Array; + } /** * Iterates through 'array' by index and performs the callback on each element of array until the callback diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index e8fd0d2a069..331ada0cbe0 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2296,7 +2296,6 @@ "category": "Error", "code": 6064 }, - "Enables experimental support for ES7 decorators.": { "category": "Message", "code": 6065 @@ -2469,6 +2468,18 @@ "category": "Message", "code": 6109 }, + "Base url: '{0}'.": { + "category": "Message", + "code": 6110 + }, + "Option '{0}' should have array of strings as a value.": { + "category": "Error", + "code": 6111 + }, + "Checking if '{0}' is the longest matching prefix for '{1}' - '{2}'.": { + "category": "Message", + "code": 6112 + }, "Variable '{0}' implicitly has an '{1}' type.": { "category": "Error", "code": 7005 diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 66944354c40..50c6b05963d 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -179,6 +179,10 @@ namespace ts { // NOTE: traceEnabled check is delibirately no inside the 'trace' at evert callside to avoid runtime impact of calling vararg function const traceEnabled = isTraceEnabled(compilerOptions, host); + if (traceEnabled) { + trace(host, Diagnostics.Base_url_Colon_0, baseUrl); + } + if (isRootedDiskPath(moduleName)) { if (traceEnabled) { trace(host, Diagnostics.Resolving_rooted_module_name_0_use_it_as_a_candidate_location, moduleName); @@ -211,6 +215,7 @@ namespace ts { function baseUrlResolveRelativeModuleName(moduleName: string, containingFile: string, baseUrl: string, supportedExtensions: string[], compilerOptions: CompilerOptions, host: ModuleResolutionHost, traceEnabled: boolean): ResolvedModuleWithFailedLookupLocations { const failedLookupLocations: string[] = []; + // we always pass absolute path to containing file so candidate location is also absolute const containingDirectory = getDirectoryPath(containingFile); const candidate = normalizePath(combinePaths(containingDirectory, moduleName)); @@ -225,14 +230,24 @@ namespace ts { let matchedPrefix: string; for (const rootDir of compilerOptions.rootDirs) { - let normalizedRoot = getNormalizedAbsolutePath(rootDir, baseUrl); + // rootDirs are expected to be absolute + let normalizedRoot = normalizePath(rootDir); if (!endsWith(normalizedRoot, directorySeparator)) { normalizedRoot += directorySeparator; } - if (startsWith(candidate, normalizedRoot) && (matchedPrefix === undefined || matchedPrefix.length < normalizedRoot.length)) { + const isLongestMatchingPrefix = + startsWith(candidate, normalizedRoot) && + (matchedPrefix === undefined || matchedPrefix.length < normalizedRoot.length); + + if (traceEnabled) { + trace(host, Diagnostics.Checking_if_0_is_the_longest_matching_prefix_for_1_2, normalizedRoot, candidate, isLongestMatchingPrefix); + } + + if (isLongestMatchingPrefix) { matchedPrefix = normalizedRoot; } } + if (matchedPrefix) { const suffix = candidate.substr(matchedPrefix.length); if (traceEnabled) { @@ -241,19 +256,20 @@ namespace ts { return baseUrlResolveNonRelativeModuleName(suffix, baseUrl, supportedExtensions, compilerOptions, host, traceEnabled); } - return { resolvedModule: undefined, failedLookupLocations }; + + // rootDirs does not contain prefix for candidate - fallthrough to load file from candidate location. } else { if (traceEnabled) { trace(host, Diagnostics.rootDirs_option_is_not_specified_using_0_as_candidate_location, candidate); } - - const resolvedFileName = loadModuleFromFile(supportedExtensions, candidate, failedLookupLocations, host, traceEnabled); - return { - resolvedModule: resolvedFileName ? { resolvedFileName } : undefined, - failedLookupLocations - }; } + + const resolvedFileName = loadModuleFromFile(supportedExtensions, candidate, failedLookupLocations, host, traceEnabled); + return { + resolvedModule: resolvedFileName ? { resolvedFileName } : undefined, + failedLookupLocations + }; } function baseUrlResolveNonRelativeModuleName(moduleName: string, baseUrl: string, supportedExtensions: string[], compilerOptions: CompilerOptions, host: ModuleResolutionHost, traceEnabled: boolean): ResolvedModuleWithFailedLookupLocations { diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 97344f4242e..7167d1e8f9a 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -1005,6 +1005,9 @@ namespace Harness { if (options.inferredBaseUrl) { options.inferredBaseUrl = ts.getNormalizedAbsolutePath(options.inferredBaseUrl, currentDirectory); } + if (options.rootDirs) { + options.rootDirs = ts.map(options.rootDirs, d => ts.getNormalizedAbsolutePath(d, currentDirectory)); + } const programFiles: TestFile[] = inputFiles.slice(); // Files from built\local that are requested by test "@includeBuiltFiles" to be in the context. diff --git a/tests/cases/compiler/pathMappingBasedModuleResolution10_2.ts b/tests/cases/compiler/pathMappingBasedModuleResolution10_2.ts index bd8942e1df1..754df23f4bf 100644 --- a/tests/cases/compiler/pathMappingBasedModuleResolution10_2.ts +++ b/tests/cases/compiler/pathMappingBasedModuleResolution10_2.ts @@ -14,8 +14,8 @@ ] }, "rootDirs": [ - ".", - "./generated" + "./src/", + "./src/generated" ] } } diff --git a/tests/cases/unittests/moduleResolution.ts b/tests/cases/unittests/moduleResolution.ts index 4bb076108eb..b6ee19f6de2 100644 --- a/tests/cases/unittests/moduleResolution.ts +++ b/tests/cases/unittests/moduleResolution.ts @@ -485,8 +485,8 @@ import b = require("./moduleB.ts"); ] }, rootDirs: [ - ".", - "./generated/" + "/root", + "/root/generated/" ] }; {