@@ -1057,7 +1057,7 @@ namespace ts {
1057
1057
errors . push ( createDiagnosticForNodeInSourceFile ( sourceFile , element . name , extraKeyDiagnosticMessage , keyText ) ) ;
1058
1058
}
1059
1059
const value = convertPropertyValueToJson ( element . initializer , option ) ;
1060
- if ( typeof keyText !== "undefined" && typeof value !== "undefined" ) {
1060
+ if ( typeof keyText !== "undefined" ) {
1061
1061
result [ keyText ] = value ;
1062
1062
// Notify key value set, if user asked for it
1063
1063
if ( jsonConversionNotifier &&
@@ -1104,7 +1104,7 @@ namespace ts {
1104
1104
return false ;
1105
1105
1106
1106
case SyntaxKind . NullKeyword :
1107
- reportInvalidOptionValue ( ! ! option ) ;
1107
+ reportInvalidOptionValue ( option && option . name === "extends" ) ; // "extends" is the only option we don't allow null/undefined for
1108
1108
return null ; // tslint:disable-line:no-null-keyword
1109
1109
1110
1110
case SyntaxKind . StringLiteral :
@@ -1189,6 +1189,7 @@ namespace ts {
1189
1189
1190
1190
function isCompilerOptionsValue ( option : CommandLineOption , value : any ) : value is CompilerOptionsValue {
1191
1191
if ( option ) {
1192
+ if ( isNullOrUndefined ( value ) ) return true ; // All options are undefinable/nullable
1192
1193
if ( option . type === "list" ) {
1193
1194
return isArray ( value ) ;
1194
1195
}
@@ -1379,6 +1380,17 @@ namespace ts {
1379
1380
}
1380
1381
}
1381
1382
1383
+ function isNullOrUndefined ( x : any ) : x is null | undefined {
1384
+ // tslint:disable-next-line:no-null-keyword
1385
+ return x === undefined || x === null ;
1386
+ }
1387
+
1388
+ function directoryOfCombinedPath ( fileName : string , basePath : string ) {
1389
+ // Use the `identity` function to avoid canonicalizing the path, as it must remain noncanonical
1390
+ // until consistient casing errors are reported
1391
+ return getDirectoryPath ( toPath ( fileName , basePath , identity ) ) ;
1392
+ }
1393
+
1382
1394
/**
1383
1395
* Parse the contents of a config file from json or json source file (tsconfig.json).
1384
1396
* @param json The contents of the config file to parse
@@ -1419,7 +1431,7 @@ namespace ts {
1419
1431
1420
1432
function getFileNames ( ) : ExpandResult {
1421
1433
let fileNames : ReadonlyArray < string > ;
1422
- if ( hasProperty ( raw , "files" ) ) {
1434
+ if ( hasProperty ( raw , "files" ) && ! isNullOrUndefined ( raw [ "files" ] ) ) {
1423
1435
if ( isArray ( raw [ "files" ] ) ) {
1424
1436
fileNames = < ReadonlyArray < string > > raw [ "files" ] ;
1425
1437
if ( fileNames . length === 0 ) {
@@ -1432,7 +1444,7 @@ namespace ts {
1432
1444
}
1433
1445
1434
1446
let includeSpecs : ReadonlyArray < string > ;
1435
- if ( hasProperty ( raw , "include" ) ) {
1447
+ if ( hasProperty ( raw , "include" ) && ! isNullOrUndefined ( raw [ "include" ] ) ) {
1436
1448
if ( isArray ( raw [ "include" ] ) ) {
1437
1449
includeSpecs = < ReadonlyArray < string > > raw [ "include" ] ;
1438
1450
}
@@ -1442,7 +1454,7 @@ namespace ts {
1442
1454
}
1443
1455
1444
1456
let excludeSpecs : ReadonlyArray < string > ;
1445
- if ( hasProperty ( raw , "exclude" ) ) {
1457
+ if ( hasProperty ( raw , "exclude" ) && ! isNullOrUndefined ( raw [ "exclude" ] ) ) {
1446
1458
if ( isArray ( raw [ "exclude" ] ) ) {
1447
1459
excludeSpecs = < ReadonlyArray < string > > raw [ "exclude" ] ;
1448
1460
}
@@ -1461,7 +1473,7 @@ namespace ts {
1461
1473
includeSpecs = [ "**/*" ] ;
1462
1474
}
1463
1475
1464
- const result = matchFileNames ( fileNames , includeSpecs , excludeSpecs , basePath , options , host , errors , extraFileExtensions , sourceFile ) ;
1476
+ const result = matchFileNames ( fileNames , includeSpecs , excludeSpecs , configFileName ? directoryOfCombinedPath ( configFileName , basePath ) : basePath , options , host , errors , extraFileExtensions , sourceFile ) ;
1465
1477
1466
1478
if ( result . fileNames . length === 0 && ! hasProperty ( raw , "files" ) && resolutionStack . length === 0 ) {
1467
1479
errors . push (
@@ -1552,7 +1564,7 @@ namespace ts {
1552
1564
host : ParseConfigHost ,
1553
1565
basePath : string ,
1554
1566
getCanonicalFileName : ( fileName : string ) => string ,
1555
- configFileName : string ,
1567
+ configFileName : string | undefined ,
1556
1568
errors : Push < Diagnostic >
1557
1569
) : ParsedTsconfig {
1558
1570
if ( hasProperty ( json , "excludes" ) ) {
@@ -1571,7 +1583,8 @@ namespace ts {
1571
1583
errors . push ( createCompilerDiagnostic ( Diagnostics . Compiler_option_0_requires_a_value_of_type_1 , "extends" , "string" ) ) ;
1572
1584
}
1573
1585
else {
1574
- extendedConfigPath = getExtendsConfigPath ( json . extends , host , basePath , getCanonicalFileName , errors , createCompilerDiagnostic ) ;
1586
+ const newBase = configFileName ? directoryOfCombinedPath ( configFileName , basePath ) : basePath ;
1587
+ extendedConfigPath = getExtendsConfigPath ( json . extends , host , newBase , getCanonicalFileName , errors , createCompilerDiagnostic ) ;
1575
1588
}
1576
1589
}
1577
1590
return { raw : json , options, typeAcquisition, extendedConfigPath } ;
@@ -1582,7 +1595,7 @@ namespace ts {
1582
1595
host : ParseConfigHost ,
1583
1596
basePath : string ,
1584
1597
getCanonicalFileName : ( fileName : string ) => string ,
1585
- configFileName : string ,
1598
+ configFileName : string | undefined ,
1586
1599
errors : Push < Diagnostic >
1587
1600
) : ParsedTsconfig {
1588
1601
const options = getDefaultCompilerOptions ( configFileName ) ;
@@ -1603,10 +1616,11 @@ namespace ts {
1603
1616
onSetValidOptionKeyValueInRoot ( key : string , _keyNode : PropertyName , value : CompilerOptionsValue , valueNode : Expression ) {
1604
1617
switch ( key ) {
1605
1618
case "extends" :
1619
+ const newBase = configFileName ? directoryOfCombinedPath ( configFileName , basePath ) : basePath ;
1606
1620
extendedConfigPath = getExtendsConfigPath (
1607
1621
< string > value ,
1608
1622
host ,
1609
- basePath ,
1623
+ newBase ,
1610
1624
getCanonicalFileName ,
1611
1625
errors ,
1612
1626
( message , arg0 ) =>
@@ -1803,6 +1817,7 @@ namespace ts {
1803
1817
}
1804
1818
1805
1819
function normalizeOptionValue ( option : CommandLineOption , basePath : string , value : any ) : CompilerOptionsValue {
1820
+ if ( isNullOrUndefined ( value ) ) return undefined ;
1806
1821
if ( option . type === "list" ) {
1807
1822
const listOption = < CommandLineOptionOfListType > option ;
1808
1823
if ( listOption . element . isFilePath || typeof listOption . element . type !== "string" ) {
@@ -1827,6 +1842,7 @@ namespace ts {
1827
1842
}
1828
1843
1829
1844
function convertJsonOptionOfCustomType ( opt : CommandLineOptionOfCustomType , value : string , errors : Push < Diagnostic > ) {
1845
+ if ( isNullOrUndefined ( value ) ) return undefined ;
1830
1846
const key = value . toLowerCase ( ) ;
1831
1847
const val = opt . type . get ( key ) ;
1832
1848
if ( val !== undefined ) {
@@ -1977,7 +1993,7 @@ namespace ts {
1977
1993
// remove a literal file.
1978
1994
if ( fileNames ) {
1979
1995
for ( const fileName of fileNames ) {
1980
- const file = combinePaths ( basePath , fileName ) ;
1996
+ const file = getNormalizedAbsolutePath ( fileName , basePath ) ;
1981
1997
literalFileMap . set ( keyMapper ( file ) , file ) ;
1982
1998
}
1983
1999
}
0 commit comments