@@ -1151,9 +1151,12 @@ export class ConfigOptions {
11511151 initializeFromJson ( configObj : any , configDirUri : Uri , serviceProvider : ServiceProvider , host : Host ) {
11521152 this . initializedFromJson = true ;
11531153 const console = serviceProvider . tryGet ( ServiceKeys . console ) ?? new NullConsole ( ) ;
1154+ const configObjKeys = configObj && typeof configObj === 'object' ? Object . getOwnPropertyNames ( configObj ) : [ ] ;
1155+ const unusedConfigKeys = new Set < string > ( configObjKeys ) ;
11541156
11551157 // Read the "include" entry.
11561158 if ( configObj . include !== undefined ) {
1159+ unusedConfigKeys . delete ( 'include' ) ;
11571160 if ( ! Array . isArray ( configObj . include ) ) {
11581161 console . error ( `Config "include" entry must contain an array.` ) ;
11591162 } else {
@@ -1173,6 +1176,7 @@ export class ConfigOptions {
11731176
11741177 // Read the "exclude" entry.
11751178 if ( configObj . exclude !== undefined ) {
1179+ unusedConfigKeys . delete ( 'exclude' ) ;
11761180 if ( ! Array . isArray ( configObj . exclude ) ) {
11771181 console . error ( `Config "exclude" entry must contain an array.` ) ;
11781182 } else {
@@ -1192,6 +1196,7 @@ export class ConfigOptions {
11921196
11931197 // Read the "ignore" entry.
11941198 if ( configObj . ignore !== undefined ) {
1199+ unusedConfigKeys . delete ( 'ignore' ) ;
11951200 if ( ! Array . isArray ( configObj . ignore ) ) {
11961201 console . error ( `Config "ignore" entry must contain an array.` ) ;
11971202 } else {
@@ -1213,6 +1218,7 @@ export class ConfigOptions {
12131218
12141219 // Read the "strict" entry.
12151220 if ( configObj . strict !== undefined ) {
1221+ unusedConfigKeys . delete ( 'strict' ) ;
12161222 if ( ! Array . isArray ( configObj . strict ) ) {
12171223 console . error ( `Config "strict" entry must contain an array.` ) ;
12181224 } else {
@@ -1232,6 +1238,7 @@ export class ConfigOptions {
12321238
12331239 // If there is a "typeCheckingMode", it can override the provided setting.
12341240 if ( configObj . typeCheckingMode !== undefined ) {
1241+ unusedConfigKeys . delete ( 'typeCheckingMode' ) ;
12351242 if (
12361243 configObj . typeCheckingMode === 'off' ||
12371244 configObj . typeCheckingMode === 'basic' ||
@@ -1245,6 +1252,7 @@ export class ConfigOptions {
12451252 }
12461253
12471254 if ( configObj . useLibraryCodeForTypes !== undefined ) {
1255+ unusedConfigKeys . delete ( 'useLibraryCodeForTypes' ) ;
12481256 if ( typeof configObj . useLibraryCodeForTypes === 'boolean' ) {
12491257 this . useLibraryCodeForTypes = configObj . useLibraryCodeForTypes ;
12501258 } else {
@@ -1255,6 +1263,7 @@ export class ConfigOptions {
12551263 // Apply overrides from the config file for the boolean rules.
12561264 const configRuleSet = { ...this . diagnosticRuleSet } ;
12571265 getBooleanDiagnosticRules ( /* includeNonOverridable */ true ) . forEach ( ( ruleName ) => {
1266+ unusedConfigKeys . delete ( ruleName ) ;
12581267 ( configRuleSet as any ) [ ruleName ] = this . _convertBoolean (
12591268 configObj [ ruleName ] ,
12601269 ruleName ,
@@ -1264,6 +1273,7 @@ export class ConfigOptions {
12641273
12651274 // Apply overrides from the config file for the diagnostic level rules.
12661275 getDiagLevelDiagnosticRules ( ) . forEach ( ( ruleName ) => {
1276+ unusedConfigKeys . delete ( ruleName ) ;
12671277 ( configRuleSet as any ) [ ruleName ] = this . _convertDiagnosticLevel (
12681278 configObj [ ruleName ] ,
12691279 ruleName ,
@@ -1274,6 +1284,7 @@ export class ConfigOptions {
12741284
12751285 // Read the "venvPath".
12761286 if ( configObj . venvPath !== undefined ) {
1287+ unusedConfigKeys . delete ( 'venvPath' ) ;
12771288 if ( typeof configObj . venvPath !== 'string' ) {
12781289 console . error ( `Config "venvPath" field must contain a string.` ) ;
12791290 } else {
@@ -1283,6 +1294,7 @@ export class ConfigOptions {
12831294
12841295 // Read the "venv" name.
12851296 if ( configObj . venv !== undefined ) {
1297+ unusedConfigKeys . delete ( 'venv' ) ;
12861298 if ( typeof configObj . venv !== 'string' ) {
12871299 console . error ( `Config "venv" field must contain a string.` ) ;
12881300 } else {
@@ -1293,6 +1305,7 @@ export class ConfigOptions {
12931305 // Read the config "extraPaths".
12941306 const configExtraPaths : Uri [ ] = [ ] ;
12951307 if ( configObj . extraPaths !== undefined ) {
1308+ unusedConfigKeys . delete ( 'extraPaths' ) ;
12961309 if ( ! Array . isArray ( configObj . extraPaths ) ) {
12971310 console . error ( `Config "extraPaths" field must contain an array.` ) ;
12981311 } else {
@@ -1310,6 +1323,7 @@ export class ConfigOptions {
13101323
13111324 // Read the default "pythonVersion".
13121325 if ( configObj . pythonVersion !== undefined ) {
1326+ unusedConfigKeys . delete ( 'pythonVersion' ) ;
13131327 if ( typeof configObj . pythonVersion === 'string' ) {
13141328 const version = PythonVersion . fromString ( configObj . pythonVersion ) ;
13151329 if ( version ) {
@@ -1324,6 +1338,7 @@ export class ConfigOptions {
13241338
13251339 // Read the default "pythonPlatform".
13261340 if ( configObj . pythonPlatform !== undefined ) {
1341+ unusedConfigKeys . delete ( 'pythonPlatform' ) ;
13271342 if ( typeof configObj . pythonPlatform !== 'string' ) {
13281343 console . error ( `Config "pythonPlatform" field must contain a string.` ) ;
13291344 } else {
@@ -1335,7 +1350,8 @@ export class ConfigOptions {
13351350 // or supported. It was added specifically to improve initialization
13361351 // performance for playgrounds or web-based environments where native
13371352 // libraries will not be present.
1338- if ( configObj . skipNativeLibraries ) {
1353+ if ( configObj . skipNativeLibraries !== undefined ) {
1354+ unusedConfigKeys . delete ( 'skipNativeLibraries' ) ;
13391355 if ( typeof configObj . skipNativeLibraries === 'boolean' ) {
13401356 this . skipNativeLibraries = configObj . skipNativeLibraries ;
13411357 } else {
@@ -1345,6 +1361,7 @@ export class ConfigOptions {
13451361
13461362 // Read the "typeshedPath" setting.
13471363 if ( configObj . typeshedPath !== undefined ) {
1364+ unusedConfigKeys . delete ( 'typeshedPath' ) ;
13481365 if ( typeof configObj . typeshedPath !== 'string' ) {
13491366 console . error ( `Config "typeshedPath" field must contain a string.` ) ;
13501367 } else {
@@ -1358,6 +1375,7 @@ export class ConfigOptions {
13581375
13591376 // Keep this for backward compatibility
13601377 if ( configObj . typingsPath !== undefined ) {
1378+ unusedConfigKeys . delete ( 'typingsPath' ) ;
13611379 if ( typeof configObj . typingsPath !== 'string' ) {
13621380 console . error ( `Config "typingsPath" field must contain a string.` ) ;
13631381 } else {
@@ -1367,6 +1385,7 @@ export class ConfigOptions {
13671385 }
13681386
13691387 if ( configObj . stubPath !== undefined ) {
1388+ unusedConfigKeys . delete ( 'stubPath' ) ;
13701389 if ( typeof configObj . stubPath !== 'string' ) {
13711390 console . error ( `Config "stubPath" field must contain a string.` ) ;
13721391 } else {
@@ -1378,6 +1397,7 @@ export class ConfigOptions {
13781397 // Don't initialize to a default value because we want the command-line "verbose"
13791398 // switch to apply if this setting isn't specified in the config file.
13801399 if ( configObj . verboseOutput !== undefined ) {
1400+ unusedConfigKeys . delete ( 'verboseOutput' ) ;
13811401 if ( typeof configObj . verboseOutput !== 'boolean' ) {
13821402 console . error ( `Config "verboseOutput" field must be true or false.` ) ;
13831403 } else {
@@ -1387,6 +1407,7 @@ export class ConfigOptions {
13871407
13881408 // Read the "defineConstant" setting.
13891409 if ( configObj . defineConstant !== undefined ) {
1410+ unusedConfigKeys . delete ( 'defineConstant' ) ;
13901411 if ( typeof configObj . defineConstant !== 'object' || Array . isArray ( configObj . defineConstant ) ) {
13911412 console . error ( `Config "defineConstant" field must contain a map indexed by constant names.` ) ;
13921413 } else {
@@ -1405,6 +1426,7 @@ export class ConfigOptions {
14051426
14061427 // Read the "useLibraryCodeForTypes" setting.
14071428 if ( configObj . useLibraryCodeForTypes !== undefined ) {
1429+ unusedConfigKeys . delete ( 'useLibraryCodeForTypes' ) ;
14081430 if ( typeof configObj . useLibraryCodeForTypes !== 'boolean' ) {
14091431 console . error ( `Config "useLibraryCodeForTypes" field must be true or false.` ) ;
14101432 } else {
@@ -1414,6 +1436,7 @@ export class ConfigOptions {
14141436
14151437 // Read the "autoImportCompletions" setting.
14161438 if ( configObj . autoImportCompletions !== undefined ) {
1439+ unusedConfigKeys . delete ( 'autoImportCompletions' ) ;
14171440 if ( typeof configObj . autoImportCompletions !== 'boolean' ) {
14181441 console . error ( `Config "autoImportCompletions" field must be true or false.` ) ;
14191442 } else {
@@ -1423,6 +1446,7 @@ export class ConfigOptions {
14231446
14241447 // Read the "indexing" setting.
14251448 if ( configObj . indexing !== undefined ) {
1449+ unusedConfigKeys . delete ( 'indexing' ) ;
14261450 if ( typeof configObj . indexing !== 'boolean' ) {
14271451 console . error ( `Config "indexing" field must be true or false.` ) ;
14281452 } else {
@@ -1432,6 +1456,7 @@ export class ConfigOptions {
14321456
14331457 // Read the "logTypeEvaluationTime" setting.
14341458 if ( configObj . logTypeEvaluationTime !== undefined ) {
1459+ unusedConfigKeys . delete ( 'logTypeEvaluationTime' ) ;
14351460 if ( typeof configObj . logTypeEvaluationTime !== 'boolean' ) {
14361461 console . error ( `Config "logTypeEvaluationTime" field must be true or false.` ) ;
14371462 } else {
@@ -1441,6 +1466,7 @@ export class ConfigOptions {
14411466
14421467 // Read the "typeEvaluationTimeThreshold" setting.
14431468 if ( configObj . typeEvaluationTimeThreshold !== undefined ) {
1469+ unusedConfigKeys . delete ( 'typeEvaluationTimeThreshold' ) ;
14441470 if ( typeof configObj . typeEvaluationTimeThreshold !== 'number' ) {
14451471 console . error ( `Config "typeEvaluationTimeThreshold" field must be a number.` ) ;
14461472 } else {
@@ -1450,6 +1476,7 @@ export class ConfigOptions {
14501476
14511477 // Read the "functionSignatureDisplay" setting.
14521478 if ( configObj . functionSignatureDisplay !== undefined ) {
1479+ unusedConfigKeys . delete ( 'functionSignatureDisplay' ) ;
14531480 if ( typeof configObj . functionSignatureDisplay !== 'string' ) {
14541481 console . error ( `Config "functionSignatureDisplay" field must be true or false.` ) ;
14551482 } else {
@@ -1461,6 +1488,13 @@ export class ConfigOptions {
14611488 }
14621489 }
14631490 }
1491+
1492+ unusedConfigKeys . delete ( 'executionEnvironments' ) ;
1493+ unusedConfigKeys . delete ( 'extends' ) ;
1494+
1495+ Array . from ( unusedConfigKeys ) . forEach ( ( unknownKey ) => {
1496+ console . error ( `Config contains unrecognized setting "${ unknownKey } ".` ) ;
1497+ } ) ;
14641498 }
14651499
14661500 static resolveExtends ( configObj : any , configDirUri : Uri ) : Uri | undefined {
@@ -1626,6 +1660,9 @@ export class ConfigOptions {
16261660 configExtraPaths : Uri [ ]
16271661 ) : ExecutionEnvironment | undefined {
16281662 try {
1663+ const envObjKeys = envObj && typeof envObj === 'object' ? Object . getOwnPropertyNames ( envObj ) : [ ] ;
1664+ const unusedEnvKeys = new Set < string > ( envObjKeys ) ;
1665+
16291666 const newExecEnv = new ExecutionEnvironment (
16301667 this . _getEnvironmentName ( ) ,
16311668 configDirUri ,
@@ -1636,13 +1673,15 @@ export class ConfigOptions {
16361673 ) ;
16371674
16381675 // Validate the root.
1676+ unusedEnvKeys . delete ( 'root' ) ;
16391677 if ( envObj . root && typeof envObj . root === 'string' ) {
16401678 newExecEnv . root = configDirUri . resolvePaths ( envObj . root ) ;
16411679 } else {
16421680 console . error ( `Config executionEnvironments index ${ index } : missing root value.` ) ;
16431681 }
16441682
16451683 // Validate the extraPaths.
1684+ unusedEnvKeys . delete ( 'extraPaths' ) ;
16461685 if ( envObj . extraPaths ) {
16471686 if ( ! Array . isArray ( envObj . extraPaths ) ) {
16481687 console . error (
@@ -1668,6 +1707,7 @@ export class ConfigOptions {
16681707 }
16691708
16701709 // Validate the pythonVersion.
1710+ unusedEnvKeys . delete ( 'pythonVersion' ) ;
16711711 if ( envObj . pythonVersion ) {
16721712 if ( typeof envObj . pythonVersion === 'string' ) {
16731713 const version = PythonVersion . fromString ( envObj . pythonVersion ) ;
@@ -1682,6 +1722,7 @@ export class ConfigOptions {
16821722 }
16831723
16841724 // Validate the pythonPlatform.
1725+ unusedEnvKeys . delete ( 'pythonPlatform' ) ;
16851726 if ( envObj . pythonPlatform ) {
16861727 if ( typeof envObj . pythonPlatform === 'string' ) {
16871728 newExecEnv . pythonPlatform = envObj . pythonPlatform ;
@@ -1691,6 +1732,7 @@ export class ConfigOptions {
16911732 }
16921733
16931734 // Validate the name.
1735+ unusedEnvKeys . delete ( 'name' ) ;
16941736 if ( envObj . name ) {
16951737 if ( typeof envObj . name === 'string' ) {
16961738 newExecEnv . name = envObj . name ;
@@ -1701,6 +1743,7 @@ export class ConfigOptions {
17011743
17021744 // Apply overrides from the config file for the boolean overrides.
17031745 getBooleanDiagnosticRules ( /* includeNonOverridable */ true ) . forEach ( ( ruleName ) => {
1746+ unusedEnvKeys . delete ( ruleName ) ;
17041747 ( newExecEnv . diagnosticRuleSet as any ) [ ruleName ] = this . _convertBoolean (
17051748 envObj [ ruleName ] ,
17061749 ruleName ,
@@ -1710,13 +1753,18 @@ export class ConfigOptions {
17101753
17111754 // Apply overrides from the config file for the diagnostic level overrides.
17121755 getDiagLevelDiagnosticRules ( ) . forEach ( ( ruleName ) => {
1756+ unusedEnvKeys . delete ( ruleName ) ;
17131757 ( newExecEnv . diagnosticRuleSet as any ) [ ruleName ] = this . _convertDiagnosticLevel (
17141758 envObj [ ruleName ] ,
17151759 ruleName ,
17161760 newExecEnv . diagnosticRuleSet [ ruleName ] as DiagnosticLevel
17171761 ) ;
17181762 } ) ;
17191763
1764+ Array . from ( unusedEnvKeys ) . forEach ( ( unknownKey ) => {
1765+ console . error ( `Config executionEnvironments index ${ index } : unrecognized setting "${ unknownKey } ".` ) ;
1766+ } ) ;
1767+
17201768 return newExecEnv ;
17211769 } catch {
17221770 console . error ( `Config executionEnvironments index ${ index } is not accessible.` ) ;
0 commit comments