Skip to content

Commit 537fee1

Browse files
committed
Resolve diagnostics conflict
2 parents 8cadf56 + 02334d8 commit 537fee1

File tree

65 files changed

+1583
-435
lines changed

Some content is hidden

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

65 files changed

+1583
-435
lines changed

Jakefile.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ var harnessSources = harnessCoreSources.concat([
216216
"moduleResolution.ts",
217217
"tsconfigParsing.ts",
218218
"commandLineParsing.ts",
219+
"configurationExtension.ts",
219220
"convertCompilerOptionsFromJson.ts",
220221
"convertTypingOptionsFromJson.ts",
221222
"tsserverProjectSystem.ts",

lib/lib.es2015.proxy.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ interface ProxyHandler<T> {
1919
setPrototypeOf? (target: T, v: any): boolean;
2020
isExtensible? (target: T): boolean;
2121
preventExtensions? (target: T): boolean;
22-
getOwnPropertyDescriptor? (target: T, p: PropertyKey): PropertyDescriptor;
22+
getOwnPropertyDescriptor? (target: T, p: PropertyKey): PropertyDescriptor | undefined;
2323
has? (target: T, p: PropertyKey): boolean;
2424
get? (target: T, p: PropertyKey, receiver: any): any;
2525
set? (target: T, p: PropertyKey, value: any, receiver: any): boolean;
@@ -35,4 +35,4 @@ interface ProxyConstructor {
3535
revocable<T>(target: T, handler: ProxyHandler<T>): { proxy: T; revoke: () => void; };
3636
new <T>(target: T, handler: ProxyHandler<T>): T
3737
}
38-
declare var Proxy: ProxyConstructor;
38+
declare var Proxy: ProxyConstructor;

src/compiler/checker.ts

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -877,7 +877,8 @@ namespace ts {
877877
if (nameNotFoundMessage) {
878878
if (!errorLocation ||
879879
!checkAndReportErrorForMissingPrefix(errorLocation, name, nameArg) &&
880-
!checkAndReportErrorForExtendingInterface(errorLocation)) {
880+
!checkAndReportErrorForExtendingInterface(errorLocation) &&
881+
!checkAndReportErrorForUsingTypeAsValue(errorLocation, name, meaning)) {
881882
error(errorLocation, nameNotFoundMessage, typeof nameArg === "string" ? nameArg : declarationNameToString(nameArg));
882883
}
883884
}
@@ -987,6 +988,16 @@ namespace ts {
987988
}
988989
}
989990

991+
function checkAndReportErrorForUsingTypeAsValue(errorLocation: Node, name: string, meaning: SymbolFlags): boolean {
992+
if (meaning & (SymbolFlags.Value & ~SymbolFlags.NamespaceModule)) {
993+
const symbol = resolveSymbol(resolveName(errorLocation, name, SymbolFlags.Type & ~SymbolFlags.Value, /*nameNotFoundMessage*/undefined, /*nameArg*/ undefined));
994+
if (symbol && !(symbol.flags & SymbolFlags.NamespaceModule)) {
995+
error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here, name);
996+
return true;
997+
}
998+
}
999+
return false;
1000+
}
9901001

9911002
function checkResolvedBlockScopedVariable(result: Symbol, errorLocation: Node): void {
9921003
Debug.assert((result.flags & SymbolFlags.BlockScopedVariable) !== 0);
@@ -10869,7 +10880,7 @@ namespace ts {
1086910880
const prop = getPropertyOfType(apparentType, right.text);
1087010881
if (!prop) {
1087110882
if (right.text && !checkAndReportErrorForExtendingInterface(node)) {
10872-
error(right, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(right), typeToString(type.flags & TypeFlags.ThisType ? apparentType : type));
10883+
reportNonexistentProperty(right, type.flags & TypeFlags.ThisType ? apparentType : type);
1087310884
}
1087410885
return unknownType;
1087510886
}
@@ -10903,6 +10914,20 @@ namespace ts {
1090310914
return propType;
1090410915
}
1090510916
return getFlowTypeOfReference(node, propType, /*assumeInitialized*/ true, /*flowContainer*/ undefined);
10917+
10918+
function reportNonexistentProperty(propNode: Identifier, containingType: Type) {
10919+
let errorInfo: DiagnosticMessageChain;
10920+
if (containingType.flags & TypeFlags.Union && !(containingType.flags & TypeFlags.Primitive)) {
10921+
for (const subtype of (containingType as UnionType).types) {
10922+
if (!getPropertyOfType(subtype, propNode.text)) {
10923+
errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(propNode), typeToString(subtype));
10924+
break;
10925+
}
10926+
}
10927+
}
10928+
errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(propNode), typeToString(containingType));
10929+
diagnostics.add(createDiagnosticForNodeFromMessageChain(propNode, errorInfo));
10930+
}
1090610931
}
1090710932

1090810933
function isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean {

src/compiler/commandLineParser.ts

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -806,12 +806,45 @@ namespace ts {
806806
* @param basePath A root directory to resolve relative path entries in the config
807807
* file to. e.g. outDir
808808
*/
809-
export function parseJsonConfigFileContent(json: any, host: ParseConfigHost, basePath: string, existingOptions: CompilerOptions = {}, configFileName?: string): ParsedCommandLine {
809+
export function parseJsonConfigFileContent(json: any, host: ParseConfigHost, basePath: string, existingOptions: CompilerOptions = {}, configFileName?: string, resolutionStack: Path[] = []): ParsedCommandLine {
810810
const errors: Diagnostic[] = [];
811-
const compilerOptions: CompilerOptions = convertCompilerOptionsFromJsonWorker(json["compilerOptions"], basePath, errors, configFileName);
812-
const options = extend(existingOptions, compilerOptions);
811+
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames);
812+
const resolvedPath = toPath(configFileName || "", basePath, getCanonicalFileName);
813+
if (resolutionStack.indexOf(resolvedPath) >= 0) {
814+
return {
815+
options: {},
816+
fileNames: [],
817+
typingOptions: {},
818+
raw: json,
819+
errors: [createCompilerDiagnostic(Diagnostics.Circularity_detected_while_resolving_configuration_Colon_0, [...resolutionStack, resolvedPath].join(" -> "))],
820+
wildcardDirectories: {}
821+
};
822+
}
823+
824+
let options: CompilerOptions = convertCompilerOptionsFromJsonWorker(json["compilerOptions"], basePath, errors, configFileName);
813825
const typingOptions: TypingOptions = convertTypingOptionsFromJsonWorker(json["typingOptions"], basePath, errors, configFileName);
814826

827+
if (json["extends"]) {
828+
let [include, exclude, files, baseOptions]: [string[], string[], string[], CompilerOptions] = [undefined, undefined, undefined, {}];
829+
if (typeof json["extends"] === "string") {
830+
[include, exclude, files, baseOptions] = (tryExtendsName(json["extends"]) || [include, exclude, files, baseOptions]);
831+
}
832+
else {
833+
errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "extends", "string"));
834+
}
835+
if (include && !json["include"]) {
836+
json["include"] = include;
837+
}
838+
if (exclude && !json["exclude"]) {
839+
json["exclude"] = exclude;
840+
}
841+
if (files && !json["files"]) {
842+
json["files"] = files;
843+
}
844+
options = assign({}, baseOptions, options);
845+
}
846+
847+
options = extend(existingOptions, options);
815848
options.configFilePath = configFileName;
816849

817850
const { fileNames, wildcardDirectories } = getFileNames(errors);
@@ -825,6 +858,39 @@ namespace ts {
825858
wildcardDirectories
826859
};
827860

861+
function tryExtendsName(extendedConfig: string): [string[], string[], string[], CompilerOptions] {
862+
// 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)
863+
if (!(isRootedDiskPath(extendedConfig) || startsWith(normalizeSlashes(extendedConfig), "./") || startsWith(normalizeSlashes(extendedConfig), "../"))) {
864+
errors.push(createCompilerDiagnostic(Diagnostics.The_path_in_an_extends_options_must_be_relative_or_rooted));
865+
return;
866+
}
867+
let extendedConfigPath = toPath(extendedConfig, basePath, getCanonicalFileName);
868+
if (!host.fileExists(extendedConfigPath) && !endsWith(extendedConfigPath, ".json")) {
869+
extendedConfigPath = `${extendedConfigPath}.json` as Path;
870+
if (!host.fileExists(extendedConfigPath)) {
871+
errors.push(createCompilerDiagnostic(Diagnostics.File_0_does_not_exist, extendedConfig));
872+
return;
873+
}
874+
}
875+
const extendedResult = readConfigFile(extendedConfigPath, path => host.readFile(path));
876+
if (extendedResult.error) {
877+
errors.push(extendedResult.error);
878+
return;
879+
}
880+
const extendedDirname = getDirectoryPath(extendedConfigPath);
881+
const relativeDifference = convertToRelativePath(extendedDirname, basePath, getCanonicalFileName);
882+
const updatePath: (path: string) => string = path => isRootedDiskPath(path) ? path : combinePaths(relativeDifference, path);
883+
// Merge configs (copy the resolution stack so it is never reused between branches in potential diamond-problem scenarios)
884+
const result = parseJsonConfigFileContent(extendedResult.config, host, extendedDirname, /*existingOptions*/undefined, getBaseFileName(extendedConfigPath), resolutionStack.concat([resolvedPath]));
885+
errors.push(...result.errors);
886+
const [include, exclude, files] = map(["include", "exclude", "files"], key => {
887+
if (!json[key] && extendedResult.config[key]) {
888+
return map(extendedResult.config[key], updatePath);
889+
}
890+
});
891+
return [include, exclude, files, result.options];
892+
}
893+
828894
function getFileNames(errors: Diagnostic[]): ExpandResult {
829895
let fileNames: string[];
830896
if (hasProperty(json, "files")) {

src/compiler/core.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,20 @@ namespace ts {
377377
return result;
378378
}
379379

380+
export function mapObject<T, U>(object: MapLike<T>, f: (key: string, x: T) => [string, U]): MapLike<U> {
381+
let result: MapLike<U>;
382+
if (object) {
383+
result = {};
384+
for (const v of getOwnKeys(object)) {
385+
const [key, value]: [string, U] = f(v, object[v]) || [undefined, undefined];
386+
if (key !== undefined) {
387+
result[key] = value;
388+
}
389+
}
390+
}
391+
return result;
392+
}
393+
380394
export function concatenate<T>(array1: T[], array2: T[]): T[] {
381395
if (!array2 || !array2.length) return array1;
382396
if (!array1 || !array1.length) return array2;
@@ -639,6 +653,18 @@ namespace ts {
639653
}
640654
}
641655

656+
export function assign<T1 extends MapLike<{}>, T2, T3>(t: T1, arg1: T2, arg2: T3): T1 & T2 & T3;
657+
export function assign<T1 extends MapLike<{}>, T2>(t: T1, arg1: T2): T1 & T2;
658+
export function assign<T1 extends MapLike<{}>>(t: T1, ...args: any[]): any;
659+
export function assign<T1 extends MapLike<{}>>(t: T1, ...args: any[]) {
660+
for (const arg of args) {
661+
for (const p of getOwnKeys(arg)) {
662+
t[p] = arg[p];
663+
}
664+
}
665+
return t;
666+
}
667+
642668
/**
643669
* Reduce the properties of a map.
644670
*

src/compiler/diagnosticMessages.json

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1947,10 +1947,14 @@
19471947
"category": "Error",
19481948
"code": 2692
19491949
},
1950-
"Left side of comma operator is unused and has no side effects.": {
1950+
"'{0}' only refers to a type, but is being used as a value here.": {
19511951
"category": "Error",
19521952
"code": 2693
19531953
},
1954+
"Left side of comma operator is unused and has no side effects.": {
1955+
"category": "Error",
1956+
"code": 2694
1957+
},
19541958
"Import declaration '{0}' is using private name '{1}'.": {
19551959
"category": "Error",
19561960
"code": 4000
@@ -3047,5 +3051,14 @@
30473051
"Unknown typing option '{0}'.": {
30483052
"category": "Error",
30493053
"code": 17010
3054+
},
3055+
3056+
"Circularity detected while resolving configuration: {0}": {
3057+
"category": "Error",
3058+
"code": 18000
3059+
},
3060+
"The path in an 'extends' options must be relative or rooted.": {
3061+
"category": "Error",
3062+
"code": 18001
30503063
}
30513064
}

0 commit comments

Comments
 (0)