mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-16 15:45:27 -05:00
Allow 'paths' without 'baseUrl' (#40101)
* Allow paths without baseUrl * Remove exception for leading * paths * Add comment, remove commented code * Update baselines * Remove unnecessary default * Fix test harness * Fix baseline * Resolve relative to host.getCurrentDirectory() with createProgram API
This commit is contained in:
@@ -2509,6 +2509,13 @@ namespace ts {
|
||||
parseOwnConfigOfJson(json, host, basePath, configFileName, errors) :
|
||||
parseOwnConfigOfJsonSourceFile(sourceFile!, host, basePath, configFileName, errors);
|
||||
|
||||
if (ownConfig.options?.paths) {
|
||||
// If we end up needing to resolve relative paths from 'paths' relative to
|
||||
// the config file location, we'll need to know where that config file was.
|
||||
// Since 'paths' can be inherited from an extended config in another directory,
|
||||
// we wouldn't know which directory to use unless we store it here.
|
||||
ownConfig.options.pathsBasePath = basePath;
|
||||
}
|
||||
if (ownConfig.extendedConfigPath) {
|
||||
// copy the resolution stack so it is never reused between branches in potential diamond-problem scenarios.
|
||||
resolutionStack = resolutionStack.concat([resolvedPath]);
|
||||
|
||||
@@ -3493,10 +3493,6 @@
|
||||
"category": "Error",
|
||||
"code": 5059
|
||||
},
|
||||
"Option 'paths' cannot be used without specifying '--baseUrl' option.": {
|
||||
"category": "Error",
|
||||
"code": 5060
|
||||
},
|
||||
"Pattern '{0}' can have at most one '*' character.": {
|
||||
"category": "Error",
|
||||
"code": 5061
|
||||
@@ -3613,6 +3609,10 @@
|
||||
"category": "Error",
|
||||
"code": 5089
|
||||
},
|
||||
"Non-relative paths are not allowed when 'baseUrl' is not set. Did you forget a leading './'?": {
|
||||
"category": "Error",
|
||||
"code": 5090
|
||||
},
|
||||
|
||||
"Generates a sourcemap for each corresponding '.d.ts' file.": {
|
||||
"category": "Message",
|
||||
|
||||
@@ -788,13 +788,16 @@ namespace ts {
|
||||
}
|
||||
|
||||
function tryLoadModuleUsingPathsIfEligible(extensions: Extensions, moduleName: string, loader: ResolutionKindSpecificLoader, state: ModuleResolutionState) {
|
||||
const { baseUrl, paths } = state.compilerOptions;
|
||||
if (baseUrl && paths && !pathIsRelative(moduleName)) {
|
||||
const { baseUrl, paths, pathsBasePath } = state.compilerOptions;
|
||||
if (paths && !pathIsRelative(moduleName)) {
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.baseUrl_option_is_set_to_0_using_this_value_to_resolve_non_relative_module_name_1, baseUrl, moduleName);
|
||||
if (baseUrl) {
|
||||
trace(state.host, Diagnostics.baseUrl_option_is_set_to_0_using_this_value_to_resolve_non_relative_module_name_1, baseUrl, moduleName);
|
||||
}
|
||||
trace(state.host, Diagnostics.paths_option_is_specified_looking_for_a_pattern_to_match_module_name_0, moduleName);
|
||||
}
|
||||
return tryLoadModuleUsingPaths(extensions, moduleName, baseUrl, paths, loader, /*onlyRecordFailures*/ false, state);
|
||||
const baseDirectory = baseUrl ?? Debug.checkDefined(pathsBasePath || state.host.getCurrentDirectory?.(), "Encountered 'paths' without a 'baseUrl', config file, or host 'getCurrentDirectory'.");
|
||||
return tryLoadModuleUsingPaths(extensions, moduleName, baseDirectory, paths, loader, /*onlyRecordFailures*/ false, state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1368,6 +1371,7 @@ namespace ts {
|
||||
}
|
||||
const resolved = forEach(paths[matchedPatternText], subst => {
|
||||
const path = matchedStar ? subst.replace("*", matchedStar) : subst;
|
||||
// When baseUrl is not specified, the command line parser resolves relative paths to the config file location.
|
||||
const candidate = normalizePath(combinePaths(baseDirectory, path));
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.Trying_substitution_0_candidate_module_location_Colon_1, subst, path);
|
||||
|
||||
@@ -2994,10 +2994,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
if (options.paths && options.baseUrl === undefined) {
|
||||
createDiagnosticForOptionName(Diagnostics.Option_paths_cannot_be_used_without_specifying_baseUrl_option, "paths");
|
||||
}
|
||||
|
||||
if (options.composite) {
|
||||
if (options.declaration === false) {
|
||||
createDiagnosticForOptionName(Diagnostics.Composite_projects_may_not_disable_declaration_emit, "declaration");
|
||||
@@ -3056,6 +3052,9 @@ namespace ts {
|
||||
if (!hasZeroOrOneAsteriskCharacter(subst)) {
|
||||
createDiagnosticForOptionPathKeyValue(key, i, Diagnostics.Substitution_0_in_pattern_1_can_have_at_most_one_Asterisk_character, subst, key);
|
||||
}
|
||||
if (!options.baseUrl && !pathIsRelative(subst) && !pathIsAbsolute(subst)) {
|
||||
createDiagnosticForOptionPathKeyValue(key, i, Diagnostics.Non_relative_paths_are_not_allowed_when_baseUrl_is_not_set_Did_you_forget_a_leading_Slash);
|
||||
}
|
||||
}
|
||||
else {
|
||||
createDiagnosticForOptionPathKeyValue(key, i, Diagnostics.Substitution_0_for_pattern_1_has_incorrect_type_expected_string_got_2, subst, key, typeOfSubst);
|
||||
@@ -3339,7 +3338,7 @@ namespace ts {
|
||||
});
|
||||
}
|
||||
|
||||
function createDiagnosticForOptionPathKeyValue(key: string, valueIndex: number, message: DiagnosticMessage, arg0: string | number, arg1: string | number, arg2?: string | number) {
|
||||
function createDiagnosticForOptionPathKeyValue(key: string, valueIndex: number, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number) {
|
||||
let needCompilerDiagnostic = true;
|
||||
const pathsSyntax = getOptionPathsSyntax();
|
||||
for (const pathProp of pathsSyntax) {
|
||||
|
||||
@@ -5787,6 +5787,8 @@ namespace ts {
|
||||
outDir?: string;
|
||||
outFile?: string;
|
||||
paths?: MapLike<string[]>;
|
||||
/** The directory of the config file that specified 'paths'. Used to resolve relative paths when 'baseUrl' is absent. */
|
||||
/*@internal*/ pathsBasePath?: string;
|
||||
/*@internal*/ plugins?: PluginImport[];
|
||||
preserveConstEnums?: boolean;
|
||||
preserveSymlinks?: boolean;
|
||||
|
||||
@@ -256,7 +256,7 @@ namespace compiler {
|
||||
if (compilerOptions.skipDefaultLibCheck === undefined) compilerOptions.skipDefaultLibCheck = true;
|
||||
if (compilerOptions.noErrorTruncation === undefined) compilerOptions.noErrorTruncation = true;
|
||||
|
||||
const preProgram = ts.length(rootFiles) < 100 ? ts.createProgram(rootFiles || [], { ...compilerOptions, traceResolution: false }, host) : undefined;
|
||||
const preProgram = ts.length(rootFiles) < 100 ? ts.createProgram(rootFiles || [], { ...compilerOptions, configFile: compilerOptions.configFile, traceResolution: false }, host) : undefined;
|
||||
const preErrors = preProgram && ts.getPreEmitDiagnostics(preProgram);
|
||||
|
||||
const program = ts.createProgram(rootFiles || [], compilerOptions, host);
|
||||
|
||||
@@ -204,4 +204,20 @@ namespace ts {
|
||||
assert.isEmpty(program.getSemanticDiagnostics());
|
||||
});
|
||||
});
|
||||
|
||||
describe("unittests:: programApi:: CompilerOptions relative paths", () => {
|
||||
it("resolves relative paths by getCurrentDirectory", () => {
|
||||
const main = new documents.TextDocument("/main.ts", "import \"module\";");
|
||||
const mod = new documents.TextDocument("/lib/module.ts", "declare const foo: any;");
|
||||
|
||||
const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false, { documents: [main, mod], cwd: "/" });
|
||||
const program = createProgram(["./main.ts"], {
|
||||
paths: { "*": ["./lib/*"] }
|
||||
}, new fakes.CompilerHost(fs, { newLine: NewLineKind.LineFeed }));
|
||||
|
||||
assert.isEmpty(program.getConfigFileParsingDiagnostics());
|
||||
assert.isEmpty(program.getGlobalDiagnostics());
|
||||
assert.isEmpty(program.getSemanticDiagnostics());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user