Skip to content

Commit 0080c5f

Browse files
committed
Merge branch 'master' into get-name-of-declaration-wrapper
This PR included a fix that I already checked in this morning.
2 parents 9392342 + 750b574 commit 0080c5f

File tree

106 files changed

+3311
-1245
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

106 files changed

+3311
-1245
lines changed

src/compiler/checker.ts

Lines changed: 95 additions & 68 deletions
Large diffs are not rendered by default.

src/compiler/commandLineParser.ts

Lines changed: 125 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,58 +1088,38 @@ namespace ts {
10881088
* @param host Instance of ParseConfigHost used to enumerate files in folder.
10891089
* @param basePath A root directory to resolve relative path entries in the config
10901090
* file to. e.g. outDir
1091+
* @param resolutionStack Only present for backwards-compatibility. Should be empty.
10911092
*/
1092-
export function parseJsonConfigFileContent(json: any, host: ParseConfigHost, basePath: string, existingOptions: CompilerOptions = {}, configFileName?: string, resolutionStack: Path[] = [], extraFileExtensions: JsFileExtensionInfo[] = []): ParsedCommandLine {
1093+
export function parseJsonConfigFileContent(
1094+
json: any,
1095+
host: ParseConfigHost,
1096+
basePath: string,
1097+
existingOptions: CompilerOptions = {},
1098+
configFileName?: string,
1099+
resolutionStack: Path[] = [],
1100+
extraFileExtensions: JsFileExtensionInfo[] = [],
1101+
): ParsedCommandLine {
10931102
const errors: Diagnostic[] = [];
1094-
basePath = normalizeSlashes(basePath);
1095-
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames);
1096-
const resolvedPath = toPath(configFileName || "", basePath, getCanonicalFileName);
1097-
if (resolutionStack.indexOf(resolvedPath) >= 0) {
1098-
return {
1099-
options: {},
1100-
fileNames: [],
1101-
typeAcquisition: {},
1102-
raw: json,
1103-
errors: [createCompilerDiagnostic(Diagnostics.Circularity_detected_while_resolving_configuration_Colon_0, [...resolutionStack, resolvedPath].join(" -> "))],
1104-
wildcardDirectories: {}
1105-
};
1106-
}
11071103

1108-
let options: CompilerOptions = convertCompilerOptionsFromJsonWorker(json["compilerOptions"], basePath, errors, configFileName);
1104+
let options = (() => {
1105+
const { include, exclude, files, options, compileOnSave } = parseConfig(json, host, basePath, configFileName, resolutionStack, errors);
1106+
if (include) { json.include = include; }
1107+
if (exclude) { json.exclude = exclude; }
1108+
if (files) { json.files = files; }
1109+
if (compileOnSave !== undefined) { json.compileOnSave = compileOnSave; }
1110+
return options;
1111+
})();
1112+
1113+
options = extend(existingOptions, options);
1114+
options.configFilePath = configFileName;
1115+
11091116
// typingOptions has been deprecated and is only supported for backward compatibility purposes.
11101117
// It should be removed in future releases - use typeAcquisition instead.
11111118
const jsonOptions = json["typeAcquisition"] || json["typingOptions"];
11121119
const typeAcquisition: TypeAcquisition = convertTypeAcquisitionFromJsonWorker(jsonOptions, basePath, errors, configFileName);
11131120

1114-
let baseCompileOnSave: boolean;
1115-
if (json["extends"]) {
1116-
let [include, exclude, files, baseOptions]: [string[], string[], string[], CompilerOptions] = [undefined, undefined, undefined, {}];
1117-
if (typeof json["extends"] === "string") {
1118-
[include, exclude, files, baseCompileOnSave, baseOptions] = (tryExtendsName(json["extends"]) || [include, exclude, files, baseCompileOnSave, baseOptions]);
1119-
}
1120-
else {
1121-
errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "extends", "string"));
1122-
}
1123-
if (include && !json["include"]) {
1124-
json["include"] = include;
1125-
}
1126-
if (exclude && !json["exclude"]) {
1127-
json["exclude"] = exclude;
1128-
}
1129-
if (files && !json["files"]) {
1130-
json["files"] = files;
1131-
}
1132-
options = assign({}, baseOptions, options);
1133-
}
1134-
1135-
options = extend(existingOptions, options);
1136-
options.configFilePath = configFileName;
1137-
1138-
const { fileNames, wildcardDirectories } = getFileNames(errors);
1139-
let compileOnSave = convertCompileOnSaveOptionFromJson(json, basePath, errors);
1140-
if (baseCompileOnSave && json[compileOnSaveCommandLineOption.name] === undefined) {
1141-
compileOnSave = baseCompileOnSave;
1142-
}
1121+
const { fileNames, wildcardDirectories } = getFileNames();
1122+
const compileOnSave = convertCompileOnSaveOptionFromJson(json, basePath, errors);
11431123

11441124
return {
11451125
options,
@@ -1151,40 +1131,7 @@ namespace ts {
11511131
compileOnSave
11521132
};
11531133

1154-
function tryExtendsName(extendedConfig: string): [string[], string[], string[], boolean, CompilerOptions] {
1155-
// If the path isn't a rooted or relative path, don't try to resolve it (we reserve the right to special case module-id like paths in the future)
1156-
if (!(isRootedDiskPath(extendedConfig) || startsWith(normalizeSlashes(extendedConfig), "./") || startsWith(normalizeSlashes(extendedConfig), "../"))) {
1157-
errors.push(createCompilerDiagnostic(Diagnostics.A_path_in_an_extends_option_must_be_relative_or_rooted_but_0_is_not, extendedConfig));
1158-
return;
1159-
}
1160-
let extendedConfigPath = toPath(extendedConfig, basePath, getCanonicalFileName);
1161-
if (!host.fileExists(extendedConfigPath) && !endsWith(extendedConfigPath, ".json")) {
1162-
extendedConfigPath = `${extendedConfigPath}.json` as Path;
1163-
if (!host.fileExists(extendedConfigPath)) {
1164-
errors.push(createCompilerDiagnostic(Diagnostics.File_0_does_not_exist, extendedConfig));
1165-
return;
1166-
}
1167-
}
1168-
const extendedResult = readConfigFile(extendedConfigPath, path => host.readFile(path));
1169-
if (extendedResult.error) {
1170-
errors.push(extendedResult.error);
1171-
return;
1172-
}
1173-
const extendedDirname = getDirectoryPath(extendedConfigPath);
1174-
const relativeDifference = convertToRelativePath(extendedDirname, basePath, getCanonicalFileName);
1175-
const updatePath: (path: string) => string = path => isRootedDiskPath(path) ? path : combinePaths(relativeDifference, path);
1176-
// Merge configs (copy the resolution stack so it is never reused between branches in potential diamond-problem scenarios)
1177-
const result = parseJsonConfigFileContent(extendedResult.config, host, extendedDirname, /*existingOptions*/ undefined, getBaseFileName(extendedConfigPath), resolutionStack.concat([resolvedPath]));
1178-
errors.push(...result.errors);
1179-
const [include, exclude, files] = map(["include", "exclude", "files"], key => {
1180-
if (!json[key] && extendedResult.config[key]) {
1181-
return map(extendedResult.config[key], updatePath);
1182-
}
1183-
});
1184-
return [include, exclude, files, result.compileOnSave, result.options];
1185-
}
1186-
1187-
function getFileNames(errors: Diagnostic[]): ExpandResult {
1134+
function getFileNames(): ExpandResult {
11881135
let fileNames: string[];
11891136
if (hasProperty(json, "files")) {
11901137
if (isArray(json["files"])) {
@@ -1217,9 +1164,6 @@ namespace ts {
12171164
errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "exclude", "Array"));
12181165
}
12191166
}
1220-
else if (hasProperty(json, "excludes")) {
1221-
errors.push(createCompilerDiagnostic(Diagnostics.Unknown_option_excludes_Did_you_mean_exclude));
1222-
}
12231167
else {
12241168
// If no includes were specified, exclude common package folders and the outDir
12251169
excludeSpecs = includeSpecs ? [] : ["node_modules", "bower_components", "jspm_packages"];
@@ -1249,7 +1193,106 @@ namespace ts {
12491193
}
12501194
}
12511195

1252-
export function convertCompileOnSaveOptionFromJson(jsonOption: any, basePath: string, errors: Diagnostic[]): boolean | undefined {
1196+
interface ParsedTsconfig {
1197+
include: string[] | undefined;
1198+
exclude: string[] | undefined;
1199+
files: string[] | undefined;
1200+
options: CompilerOptions;
1201+
compileOnSave: boolean | undefined;
1202+
}
1203+
1204+
/**
1205+
* This *just* extracts options/include/exclude/files out of a config file.
1206+
* It does *not* resolve the included files.
1207+
*/
1208+
function parseConfig(
1209+
json: any,
1210+
host: ParseConfigHost,
1211+
basePath: string,
1212+
configFileName: string,
1213+
resolutionStack: Path[],
1214+
errors: Diagnostic[],
1215+
): ParsedTsconfig {
1216+
1217+
basePath = normalizeSlashes(basePath);
1218+
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames);
1219+
const resolvedPath = toPath(configFileName || "", basePath, getCanonicalFileName);
1220+
1221+
if (resolutionStack.indexOf(resolvedPath) >= 0) {
1222+
errors.push(createCompilerDiagnostic(Diagnostics.Circularity_detected_while_resolving_configuration_Colon_0, [...resolutionStack, resolvedPath].join(" -> ")));
1223+
return { include: undefined, exclude: undefined, files: undefined, options: {}, compileOnSave: undefined };
1224+
}
1225+
1226+
if (hasProperty(json, "excludes")) {
1227+
errors.push(createCompilerDiagnostic(Diagnostics.Unknown_option_excludes_Did_you_mean_exclude));
1228+
}
1229+
1230+
let options: CompilerOptions = convertCompilerOptionsFromJsonWorker(json.compilerOptions, basePath, errors, configFileName);
1231+
let include: string[] | undefined = json.include, exclude: string[] | undefined = json.exclude, files: string[] | undefined = json.files;
1232+
let compileOnSave: boolean | undefined = json.compileOnSave;
1233+
1234+
if (json.extends) {
1235+
// copy the resolution stack so it is never reused between branches in potential diamond-problem scenarios.
1236+
resolutionStack = resolutionStack.concat([resolvedPath]);
1237+
const base = getExtendedConfig(json.extends, host, basePath, getCanonicalFileName, resolutionStack, errors);
1238+
if (base) {
1239+
include = include || base.include;
1240+
exclude = exclude || base.exclude;
1241+
files = files || base.files;
1242+
if (compileOnSave === undefined) {
1243+
compileOnSave = base.compileOnSave;
1244+
}
1245+
options = assign({}, base.options, options);
1246+
}
1247+
}
1248+
1249+
return { include, exclude, files, options, compileOnSave };
1250+
}
1251+
1252+
function getExtendedConfig(
1253+
extended: any, // Usually a string.
1254+
host: ts.ParseConfigHost,
1255+
basePath: string,
1256+
getCanonicalFileName: (fileName: string) => string,
1257+
resolutionStack: Path[],
1258+
errors: Diagnostic[],
1259+
): ParsedTsconfig | undefined {
1260+
if (typeof extended !== "string") {
1261+
errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "extends", "string"));
1262+
return undefined;
1263+
}
1264+
1265+
extended = normalizeSlashes(extended);
1266+
1267+
// If the path isn't a rooted or relative path, don't try to resolve it (we reserve the right to special case module-id like paths in the future)
1268+
if (!(isRootedDiskPath(extended) || startsWith(extended, "./") || startsWith(extended, "../"))) {
1269+
errors.push(createCompilerDiagnostic(Diagnostics.A_path_in_an_extends_option_must_be_relative_or_rooted_but_0_is_not, extended));
1270+
return undefined;
1271+
}
1272+
1273+
let extendedConfigPath = toPath(extended, basePath, getCanonicalFileName);
1274+
if (!host.fileExists(extendedConfigPath) && !endsWith(extendedConfigPath, ".json")) {
1275+
extendedConfigPath = extendedConfigPath + ".json" as Path;
1276+
if (!host.fileExists(extendedConfigPath)) {
1277+
errors.push(createCompilerDiagnostic(Diagnostics.File_0_does_not_exist, extended));
1278+
return undefined;
1279+
}
1280+
}
1281+
1282+
const extendedResult = readConfigFile(extendedConfigPath, path => host.readFile(path));
1283+
if (extendedResult.error) {
1284+
errors.push(extendedResult.error);
1285+
return undefined;
1286+
}
1287+
1288+
const extendedDirname = getDirectoryPath(extendedConfigPath);
1289+
const relativeDifference = convertToRelativePath(extendedDirname, basePath, getCanonicalFileName);
1290+
const updatePath: (path: string) => string = path => isRootedDiskPath(path) ? path : combinePaths(relativeDifference, path);
1291+
const { include, exclude, files, options, compileOnSave } = parseConfig(extendedResult.config, host, extendedDirname, getBaseFileName(extendedConfigPath), resolutionStack, errors);
1292+
return { include: map(include, updatePath), exclude: map(exclude, updatePath), files: map(files, updatePath), compileOnSave, options };
1293+
}
1294+
1295+
export function convertCompileOnSaveOptionFromJson(jsonOption: any, basePath: string, errors: Diagnostic[]): boolean {
12531296
if (!hasProperty(jsonOption, compileOnSaveCommandLineOption.name)) {
12541297
return false;
12551298
}

0 commit comments

Comments
 (0)