@@ -917,19 +917,19 @@ namespace ts {
917
917
{
918
918
name : "compilerOptions" ,
919
919
type : "object" ,
920
- optionDeclarations : commandLineOptionsToMap ( optionDeclarations ) ,
920
+ elementOptions : commandLineOptionsToMap ( optionDeclarations ) ,
921
921
extraKeyDiagnosticMessage : Diagnostics . Unknown_compiler_option_0
922
922
} ,
923
923
{
924
924
name : "typingOptions" ,
925
925
type : "object" ,
926
- optionDeclarations : commandLineOptionsToMap ( typeAcquisitionDeclarations ) ,
926
+ elementOptions : commandLineOptionsToMap ( typeAcquisitionDeclarations ) ,
927
927
extraKeyDiagnosticMessage : Diagnostics . Unknown_type_acquisition_option_0
928
928
} ,
929
929
{
930
930
name : "typeAcquisition" ,
931
931
type : "object" ,
932
- optionDeclarations : commandLineOptionsToMap ( typeAcquisitionDeclarations ) ,
932
+ elementOptions : commandLineOptionsToMap ( typeAcquisitionDeclarations ) ,
933
933
extraKeyDiagnosticMessage : Diagnostics . Unknown_type_acquisition_option_0
934
934
} ,
935
935
{
@@ -967,37 +967,64 @@ namespace ts {
967
967
}
968
968
969
969
interface JsonConversionNotifier {
970
- /** Notifies options object is being set with the optionKey and optionValue is being set */
971
- onSetOptionKeyValue ( optionsObject : string , option : CommandLineOption , value : CompilerOptionsValue ) : void ;
972
- /** Notify when root key value is being set */
973
- onRootKeyValue ( key : string , propertyName : PropertyName , value : CompilerOptionsValue , node : Expression ) : void ;
970
+ /**
971
+ * Notifies parent option object is being set with the optionKey and a valid optionValue
972
+ * Currently it notifies only if there is element with type object (parentOption) and
973
+ * has element's option declarations map associated with it
974
+ * @param parentOption parent option name in which the option and value are being set
975
+ * @param option option declaration which is being set with the value
976
+ * @param value value of the option
977
+ */
978
+ onSetValidOptionKeyValueInParent ( parentOption : string , option : CommandLineOption , value : CompilerOptionsValue ) : void ;
979
+ /**
980
+ * Notify when valid root key value option is being set
981
+ * @param key option key
982
+ * @param keyNode node corresponding to node in the source file
983
+ * @param value computed value of the key
984
+ * @param ValueNode node corresponding to value in the source file
985
+ */
986
+ onSetValidOptionKeyValueInRoot ( key : string , keyNode : PropertyName , value : CompilerOptionsValue , valueNode : Expression ) : void ;
987
+ /**
988
+ * Notify when unknown root key value option is being set
989
+ * @param key option key
990
+ * @param keyNode node corresponding to node in the source file
991
+ * @param value computed value of the key
992
+ * @param ValueNode node corresponding to value in the source file
993
+ */
994
+ onSetUnknownOptionKeyValueInRoot ( key : string , keyNode : PropertyName , value : CompilerOptionsValue , valueNode : Expression ) : void ;
974
995
}
975
996
976
997
/**
977
998
* Convert the json syntax tree into the json value
978
- * @param jsonNode
979
- * @param errors
980
999
*/
981
1000
export function convertToObject ( sourceFile : JsonSourceFile , errors : Diagnostic [ ] ) : any {
982
- return convertToObjectWorker ( sourceFile , errors ) ;
1001
+ return convertToObjectWorker ( sourceFile , errors , /*knownRootOptions*/ undefined , /*jsonConversionNotifier*/ undefined ) ;
983
1002
}
984
1003
985
1004
/**
986
1005
* Convert the json syntax tree into the json value
987
- * @param jsonNode
988
- * @param errors
989
1006
*/
990
- function convertToObjectWorker ( sourceFile : JsonSourceFile , errors : Diagnostic [ ] , knownRootOptions ?: Map < CommandLineOption > , optionsIterator ?: JsonConversionNotifier ) : any {
1007
+ function convertToObjectWorker (
1008
+ sourceFile : JsonSourceFile ,
1009
+ errors : Diagnostic [ ] ,
1010
+ knownRootOptions : Map < CommandLineOption > | undefined ,
1011
+ jsonConversionNotifier : JsonConversionNotifier | undefined ) : any {
991
1012
if ( ! sourceFile . jsonObject ) {
992
1013
if ( sourceFile . endOfFileToken ) {
993
1014
return { } ;
994
1015
}
995
1016
return undefined ;
996
1017
}
997
1018
998
- return convertObjectLiteralExpressionToJson ( sourceFile . jsonObject , knownRootOptions ) ;
1019
+ return convertObjectLiteralExpressionToJson ( sourceFile . jsonObject , knownRootOptions ,
1020
+ /*extraKeyDiagnosticMessage*/ undefined , /*parentOption*/ undefined ) ;
999
1021
1000
- function convertObjectLiteralExpressionToJson ( node : ObjectLiteralExpression , knownOptions : Map < CommandLineOption > , extraKeyDiagnosticMessage ?: DiagnosticMessage , optionsObject ?: string ) : any {
1022
+ function convertObjectLiteralExpressionToJson (
1023
+ node : ObjectLiteralExpression ,
1024
+ knownOptions : Map < CommandLineOption > | undefined ,
1025
+ extraKeyDiagnosticMessage : DiagnosticMessage | undefined ,
1026
+ parentOption : string | undefined
1027
+ ) : any {
1001
1028
const result : any = { } ;
1002
1029
for ( const element of node . properties ) {
1003
1030
if ( element . kind !== SyntaxKind . PropertyAssignment ) {
@@ -1021,32 +1048,45 @@ namespace ts {
1021
1048
if ( typeof keyText !== undefined && typeof value !== undefined ) {
1022
1049
result [ keyText ] = value ;
1023
1050
// Notify key value set, if user asked for it
1024
- if ( optionsIterator &&
1025
- ( optionsObject || knownOptions === knownRootOptions ) ) {
1051
+ if ( jsonConversionNotifier &&
1052
+ // Current callbacks are only on known parent option or if we are setting values in the root
1053
+ ( parentOption || knownOptions === knownRootOptions ) ) {
1026
1054
const isValidOptionValue = isCompilerOptionsValue ( option , value ) ;
1027
- if ( optionsObject && isValidOptionValue ) {
1028
- optionsIterator . onSetOptionKeyValue ( optionsObject , option , value ) ;
1055
+ if ( parentOption ) {
1056
+ if ( isValidOptionValue ) {
1057
+ // Notify option set in the parent if its a valid option value
1058
+ jsonConversionNotifier . onSetValidOptionKeyValueInParent ( parentOption , option , value ) ;
1059
+ }
1029
1060
}
1030
- if ( knownOptions === knownRootOptions && ( isValidOptionValue || ! option ) ) {
1031
- optionsIterator . onRootKeyValue ( keyText , element . name , value , element . initializer ) ;
1061
+ else if ( knownOptions === knownRootOptions ) {
1062
+ if ( isValidOptionValue ) {
1063
+ // Notify about the valid root key value being set
1064
+ jsonConversionNotifier . onSetValidOptionKeyValueInRoot ( keyText , element . name , value , element . initializer ) ;
1065
+ }
1066
+ else if ( ! option ) {
1067
+ // Notify about the unknown root key value being set
1068
+ jsonConversionNotifier . onSetUnknownOptionKeyValueInRoot ( keyText , element . name , value , element . initializer ) ;
1069
+ }
1032
1070
}
1033
1071
}
1034
-
1035
1072
}
1036
1073
}
1037
1074
return result ;
1038
1075
}
1039
1076
1040
- function convertArrayLiteralExpressionToJson ( elements : NodeArray < Expression > , option ?: CommandLineOption ) : any [ ] {
1077
+ function convertArrayLiteralExpressionToJson (
1078
+ elements : NodeArray < Expression > ,
1079
+ elementOption : CommandLineOption | undefined
1080
+ ) : any [ ] {
1041
1081
const result : any [ ] = [ ] ;
1042
1082
for ( const element of elements ) {
1043
- result . push ( convertPropertyValueToJson ( element , option ) ) ;
1083
+ result . push ( convertPropertyValueToJson ( element , elementOption ) ) ;
1044
1084
}
1045
1085
return result ;
1046
1086
}
1047
1087
1048
- function convertPropertyValueToJson ( node : Expression , option : CommandLineOption ) : any {
1049
- switch ( node . kind ) {
1088
+ function convertPropertyValueToJson ( valueExpression : Expression , option : CommandLineOption ) : any {
1089
+ switch ( valueExpression . kind ) {
1050
1090
case SyntaxKind . TrueKeyword :
1051
1091
reportInvalidOptionValue ( option && option . type !== "boolean" ) ;
1052
1092
return true ;
@@ -1060,19 +1100,19 @@ namespace ts {
1060
1100
return null ; // tslint:disable-line:no-null-keyword
1061
1101
1062
1102
case SyntaxKind . StringLiteral :
1063
- if ( ! isDoubleQuotedString ( node ) ) {
1064
- errors . push ( createDiagnosticForNodeInSourceFile ( sourceFile , node , Diagnostics . String_literal_with_double_quotes_expected ) ) ;
1103
+ if ( ! isDoubleQuotedString ( valueExpression ) ) {
1104
+ errors . push ( createDiagnosticForNodeInSourceFile ( sourceFile , valueExpression , Diagnostics . String_literal_with_double_quotes_expected ) ) ;
1065
1105
}
1066
1106
reportInvalidOptionValue ( option && ( typeof option . type === "string" && option . type !== "string" ) ) ;
1067
- const text = ( < StringLiteral > node ) . text ;
1107
+ const text = ( < StringLiteral > valueExpression ) . text ;
1068
1108
if ( option && typeof option . type !== "string" ) {
1069
1109
const customOption = < CommandLineOptionOfCustomType > option ;
1070
1110
// Validate custom option type
1071
1111
if ( ! customOption . type . has ( text ) ) {
1072
1112
errors . push (
1073
1113
createDiagnosticForInvalidCustomType (
1074
1114
customOption ,
1075
- ( message , arg0 , arg1 ) => createDiagnosticForNodeInSourceFile ( sourceFile , node , message , arg0 , arg1 )
1115
+ ( message , arg0 , arg1 ) => createDiagnosticForNodeInSourceFile ( sourceFile , valueExpression , message , arg0 , arg1 )
1076
1116
)
1077
1117
) ;
1078
1118
}
@@ -1081,37 +1121,49 @@ namespace ts {
1081
1121
1082
1122
case SyntaxKind . NumericLiteral :
1083
1123
reportInvalidOptionValue ( option && option . type !== "number" ) ;
1084
- return Number ( ( < NumericLiteral > node ) . text ) ;
1124
+ return Number ( ( < NumericLiteral > valueExpression ) . text ) ;
1085
1125
1086
1126
case SyntaxKind . ObjectLiteralExpression :
1087
1127
reportInvalidOptionValue ( option && option . type !== "object" ) ;
1088
- const objectOption = < TsConfigOnlyOption > option ;
1089
- const optionDeclarations = option && objectOption . optionDeclarations ;
1090
- return convertObjectLiteralExpressionToJson (
1091
- < ObjectLiteralExpression > node ,
1092
- optionDeclarations ,
1093
- option && objectOption . extraKeyDiagnosticMessage ,
1094
- optionDeclarations && option . name
1095
- ) ;
1128
+ const objectLiteralExpression = < ObjectLiteralExpression > valueExpression ;
1129
+
1130
+ // Currently having element option declaration in the tsconfig with type "object"
1131
+ // determines if it needs onSetValidOptionKeyValueInParent callback or not
1132
+ // At moment there are only "compilerOptions", "typeAcquisition" and "typingOptions"
1133
+ // that satifies it and need it to modify options set in them (for normalizing file paths)
1134
+ // vs what we set in the json
1135
+ // If need arises, we can modify this interface and callbacks as needed
1136
+ if ( option ) {
1137
+ const { elementOptions, extraKeyDiagnosticMessage, name : optionName } = < TsConfigOnlyOption > option ;
1138
+ return convertObjectLiteralExpressionToJson ( objectLiteralExpression ,
1139
+ elementOptions , extraKeyDiagnosticMessage , optionName ) ;
1140
+ }
1141
+ else {
1142
+ return convertObjectLiteralExpressionToJson (
1143
+ objectLiteralExpression , /* knownOptions*/ undefined ,
1144
+ /*extraKeyDiagnosticMessage */ undefined , /*parentOption*/ undefined ) ;
1145
+ }
1096
1146
1097
1147
case SyntaxKind . ArrayLiteralExpression :
1098
1148
reportInvalidOptionValue ( option && option . type !== "list" ) ;
1099
- return convertArrayLiteralExpressionToJson ( ( < ArrayLiteralExpression > node ) . elements , option && ( < CommandLineOptionOfListType > option ) . element ) ;
1149
+ return convertArrayLiteralExpressionToJson (
1150
+ ( < ArrayLiteralExpression > valueExpression ) . elements ,
1151
+ option && ( < CommandLineOptionOfListType > option ) . element ) ;
1100
1152
}
1101
1153
1102
1154
// Not in expected format
1103
1155
if ( option ) {
1104
1156
reportInvalidOptionValue ( /*isError*/ true ) ;
1105
1157
}
1106
1158
else {
1107
- errors . push ( createDiagnosticForNodeInSourceFile ( sourceFile , node , Diagnostics . Property_value_can_only_be_string_literal_numeric_literal_true_false_null_object_literal_or_array_literal ) ) ;
1159
+ errors . push ( createDiagnosticForNodeInSourceFile ( sourceFile , valueExpression , Diagnostics . Property_value_can_only_be_string_literal_numeric_literal_true_false_null_object_literal_or_array_literal ) ) ;
1108
1160
}
1109
1161
1110
1162
return undefined ;
1111
1163
1112
1164
function reportInvalidOptionValue ( isError : boolean ) {
1113
1165
if ( isError ) {
1114
- errors . push ( createDiagnosticForNodeInSourceFile ( sourceFile , node , Diagnostics . Compiler_option_0_requires_a_value_of_type_1 , option . name , getCompilerOptionValueTypeString ( option ) ) ) ;
1166
+ errors . push ( createDiagnosticForNodeInSourceFile ( sourceFile , valueExpression , Diagnostics . Compiler_option_0_requires_a_value_of_type_1 , option . name , getCompilerOptionValueTypeString ( option ) ) ) ;
1115
1167
}
1116
1168
}
1117
1169
}
@@ -1542,15 +1594,17 @@ namespace ts {
1542
1594
let extendedConfigPath : Path ;
1543
1595
1544
1596
const optionsIterator : JsonConversionNotifier = {
1545
- onSetOptionKeyValue ( optionsObject : string , option : CommandLineOption , value : CompilerOptionsValue ) {
1546
- Debug . assert ( optionsObject === "compilerOptions" || optionsObject === "typeAcquisition" || optionsObject === "typingOptions" ) ;
1547
- const currentOption = optionsObject === "compilerOptions" ? options :
1548
- optionsObject === "typeAcquisition" ? ( typeAcquisition || ( typeAcquisition = getDefaultTypeAcquisition ( configFileName ) ) ) :
1597
+ onSetValidOptionKeyValueInParent ( parentOption : string , option : CommandLineOption , value : CompilerOptionsValue ) {
1598
+ Debug . assert ( parentOption === "compilerOptions" || parentOption === "typeAcquisition" || parentOption === "typingOptions" ) ;
1599
+ const currentOption = parentOption === "compilerOptions" ?
1600
+ options :
1601
+ parentOption === "typeAcquisition" ?
1602
+ ( typeAcquisition || ( typeAcquisition = getDefaultTypeAcquisition ( configFileName ) ) ) :
1549
1603
( typingOptionstypeAcquisition || ( typingOptionstypeAcquisition = getDefaultTypeAcquisition ( configFileName ) ) ) ;
1550
1604
1551
1605
currentOption [ option . name ] = normalizeOptionValue ( option , basePath , value ) ;
1552
1606
} ,
1553
- onRootKeyValue ( key : string , propertyName : PropertyName , value : CompilerOptionsValue , node : Expression ) {
1607
+ onSetValidOptionKeyValueInRoot ( key : string , _keyNode : PropertyName , value : CompilerOptionsValue , valueNode : Expression ) {
1554
1608
switch ( key ) {
1555
1609
case "extends" :
1556
1610
extendedConfigPath = getExtendsConfigPath (
@@ -1560,18 +1614,20 @@ namespace ts {
1560
1614
getCanonicalFileName ,
1561
1615
errors ,
1562
1616
( message , arg0 ) =>
1563
- createDiagnosticForNodeInSourceFile ( sourceFile , node , message , arg0 )
1617
+ createDiagnosticForNodeInSourceFile ( sourceFile , valueNode , message , arg0 )
1564
1618
) ;
1565
1619
return ;
1566
- case "excludes" :
1567
- errors . push ( createDiagnosticForNodeInSourceFile ( sourceFile , propertyName , Diagnostics . Unknown_option_excludes_Did_you_mean_exclude ) ) ;
1568
- return ;
1569
1620
case "files" :
1570
1621
if ( ( < string [ ] > value ) . length === 0 ) {
1571
- errors . push ( createDiagnosticForNodeInSourceFile ( sourceFile , node , Diagnostics . The_files_list_in_config_file_0_is_empty , configFileName || "tsconfig.json" ) ) ;
1622
+ errors . push ( createDiagnosticForNodeInSourceFile ( sourceFile , valueNode , Diagnostics . The_files_list_in_config_file_0_is_empty , configFileName || "tsconfig.json" ) ) ;
1572
1623
}
1573
1624
return ;
1574
1625
}
1626
+ } ,
1627
+ onSetUnknownOptionKeyValueInRoot ( key : string , keyNode : PropertyName , _value : CompilerOptionsValue , _valueNode : Expression ) {
1628
+ if ( key === "excludes" ) {
1629
+ errors . push ( createDiagnosticForNodeInSourceFile ( sourceFile , keyNode , Diagnostics . Unknown_option_excludes_Did_you_mean_exclude ) ) ;
1630
+ }
1575
1631
}
1576
1632
} ;
1577
1633
const json = convertToObjectWorker ( sourceFile , errors , getTsconfigRootOptionsMap ( ) , optionsIterator ) ;
0 commit comments