1+ /// <reference path="..\harness.ts" /> 
2+ /// <reference path="..\virtualFileSystem.ts" /> 
3+ 
4+ namespace  ts  { 
5+     const  testContents  =  { 
6+         "/dev/tsconfig.json" : `{ 
7+   "extends": "./configs/base", 
8+   "files": [ 
9+     "main.ts", 
10+     "supplemental.ts" 
11+   ] 
12+ }` , 
13+         "/dev/tsconfig.nostrictnull.json" : `{ 
14+   "extends": "./tsconfig", 
15+   "compilerOptions": { 
16+     "strictNullChecks": false 
17+   } 
18+ }` , 
19+         "/dev/configs/base.json" : `{ 
20+   "compilerOptions": { 
21+     "allowJs": true, 
22+     "noImplicitAny": true, 
23+     "strictNullChecks": true 
24+   } 
25+ }` , 
26+         "/dev/configs/tests.json" : `{ 
27+   "compilerOptions": { 
28+     "preserveConstEnums": true, 
29+     "removeComments": false, 
30+     "sourceMap": true 
31+   }, 
32+   "exclude": [ 
33+     "../tests/baselines", 
34+     "../tests/scenarios" 
35+   ], 
36+   "include": [ 
37+     "../tests/**/*.ts" 
38+   ] 
39+ }` , 
40+         "/dev/circular.json" : `{ 
41+     "extends": "./circular2", 
42+     "compilerOptions": { 
43+         "module": "amd" 
44+     } 
45+ }` , 
46+         "/dev/circular2.json" : `{ 
47+     "extends": "./circular", 
48+     "compilerOptions": { 
49+         "module": "commonjs" 
50+     } 
51+ }` , 
52+         "/dev/missing.json" : `{ 
53+     "extends": "./missing2", 
54+     "compilerOptions": { 
55+         "types": [] 
56+     } 
57+ }` , 
58+         "/dev/failure.json" : `{ 
59+     "extends": "./failure2.json", 
60+     "compilerOptions": { 
61+         "typeRoots": [] 
62+     } 
63+ }` , 
64+         "/dev/failure2.json" : `{ 
65+     "excludes": ["*.js"] 
66+ }` , 
67+         "/dev/configs/first.json" : `{ 
68+     "extends": "./base", 
69+     "compilerOptions": { 
70+         "module": "commonjs" 
71+     }, 
72+     "files": ["../main.ts"] 
73+ }` , 
74+         "/dev/configs/second.json" : `{ 
75+     "extends": "./base", 
76+     "compilerOptions": { 
77+         "module": "amd" 
78+     }, 
79+     "include": ["../supplemental.*"] 
80+ }` , 
81+         "/dev/extends.json" : `{ "extends": 42 }` , 
82+         "/dev/extends2.json" : `{ "extends": "configs/base" }` , 
83+         "/dev/main.ts" : "" , 
84+         "/dev/supplemental.ts" : "" , 
85+         "/dev/tests/unit/spec.ts" : "" , 
86+         "/dev/tests/utils.ts" : "" , 
87+         "/dev/tests/scenarios/first.json" : "" , 
88+         "/dev/tests/baselines/first/output.ts" : "" 
89+     } ; 
90+ 
91+     const  caseInsensitiveBasePath  =  "c:/dev/" ; 
92+     const  caseInsensitiveHost  =  new  Utils . MockParseConfigHost ( caseInsensitiveBasePath ,  /*useCaseSensitiveFileNames*/  false ,  mapObject ( testContents ,  ( key ,  content )  =>  [ `c:${ key }  ,  content ] ) ) ; 
93+ 
94+     const  caseSensitiveBasePath  =  "/dev/" ; 
95+     const  caseSensitiveHost  =  new  Utils . MockParseConfigHost ( caseSensitiveBasePath ,  /*useCaseSensitiveFileNames*/  true ,  testContents ) ; 
96+ 
97+     function  verifyDiagnostics ( actual : Diagnostic [ ] ,  expected : { code : number ,  category : DiagnosticCategory ,  messageText : string } [ ] )  { 
98+         assert . isTrue ( expected . length  ===  actual . length ,  `Expected error: ${ JSON . stringify ( expected ) } ${ JSON . stringify ( actual ) }  ) ; 
99+         for  ( let  i  =  0 ;  i  <  actual . length ;  i ++ )  { 
100+             const  actualError  =  actual [ i ] ; 
101+             const  expectedError  =  expected [ i ] ; 
102+             assert . equal ( actualError . code ,  expectedError . code ,  "Error code mismatch" ) ; 
103+             assert . equal ( actualError . category ,  expectedError . category ,  "Category mismatch" ) ; 
104+             assert . equal ( flattenDiagnosticMessageText ( actualError . messageText ,  "\n" ) ,  expectedError . messageText ) ; 
105+         } 
106+     } 
107+ 
108+     describe ( "Configuration Extension" ,  ( )  =>  { 
109+         forEach < [ string ,  string ,  Utils . MockParseConfigHost ] ,  void > ( [ 
110+             [ "under a case insensitive host" ,  caseInsensitiveBasePath ,  caseInsensitiveHost ] , 
111+             [ "under a case sensitive host" ,  caseSensitiveBasePath ,  caseSensitiveHost ] 
112+         ] ,  ( [ testName ,  basePath ,  host ] )  =>  { 
113+             function  testSuccess ( name : string ,  entry : string ,  expected : CompilerOptions ,  expectedFiles : string [ ] )  { 
114+                 it ( name ,  ( )  =>  { 
115+                     const  { config,  error}  =  ts . readConfigFile ( entry ,  name  =>  host . readFile ( name ) ) ; 
116+                     assert ( config  &&  ! error ,  flattenDiagnosticMessageText ( error  &&  error . messageText ,  "\n" ) ) ; 
117+                     const  parsed  =  ts . parseJsonConfigFileContent ( config ,  host ,  basePath ,  { } ,  entry ) ; 
118+                     assert ( ! parsed . errors . length ,  flattenDiagnosticMessageText ( parsed . errors [ 0 ]  &&  parsed . errors [ 0 ] . messageText ,  "\n" ) ) ; 
119+                     expected . configFilePath  =  entry ; 
120+                     assert . deepEqual ( parsed . options ,  expected ) ; 
121+                     assert . deepEqual ( parsed . fileNames ,  expectedFiles ) ; 
122+                 } ) ; 
123+             } 
124+ 
125+             function  testFailure ( name : string ,  entry : string ,  expectedDiagnostics : { code : number ,  category : DiagnosticCategory ,  messageText : string } [ ] )  { 
126+                 it ( name ,  ( )  =>  { 
127+                     const  { config,  error}  =  ts . readConfigFile ( entry ,  name  =>  host . readFile ( name ) ) ; 
128+                     assert ( config  &&  ! error ,  flattenDiagnosticMessageText ( error  &&  error . messageText ,  "\n" ) ) ; 
129+                     const  parsed  =  ts . parseJsonConfigFileContent ( config ,  host ,  basePath ,  { } ,  entry ) ; 
130+                     verifyDiagnostics ( parsed . errors ,  expectedDiagnostics ) ; 
131+                 } ) ; 
132+             } 
133+ 
134+             describe ( testName ,  ( )  =>  { 
135+                 testSuccess ( "can resolve an extension with a base extension" ,  "tsconfig.json" ,  { 
136+                     allowJs : true , 
137+                     noImplicitAny : true , 
138+                     strictNullChecks : true , 
139+                 } ,  [ 
140+                     combinePaths ( basePath ,  "main.ts" ) , 
141+                     combinePaths ( basePath ,  "supplemental.ts" ) , 
142+                 ] ) ; 
143+ 
144+                 testSuccess ( "can resolve an extension with a base extension that overrides options" ,  "tsconfig.nostrictnull.json" ,  { 
145+                     allowJs : true , 
146+                     noImplicitAny : true , 
147+                     strictNullChecks : false , 
148+                 } ,  [ 
149+                     combinePaths ( basePath ,  "main.ts" ) , 
150+                     combinePaths ( basePath ,  "supplemental.ts" ) , 
151+                 ] ) ; 
152+ 
153+                 testFailure ( "can report errors on circular imports" ,  "circular.json" ,  [ 
154+                     { 
155+                         code : 18000 , 
156+                         category : DiagnosticCategory . Error , 
157+                         messageText : `Circularity detected while resolving configuration: ${ [ combinePaths ( basePath ,  "circular.json" ) ,  combinePaths ( basePath ,  "circular2.json" ) ,  combinePaths ( basePath ,  "circular.json" ) ] . join ( " -> " ) }  
158+                     } 
159+                 ] ) ; 
160+ 
161+                 testFailure ( "can report missing configurations" ,  "missing.json" ,  [ { 
162+                     code : 6096 , 
163+                     category : DiagnosticCategory . Message , 
164+                     messageText : `File './missing2' does not exist.` 
165+                 } ] ) ; 
166+ 
167+                 testFailure ( "can report errors in extended configs" ,  "failure.json" ,  [ { 
168+                     code : 6114 , 
169+                     category : DiagnosticCategory . Error , 
170+                     messageText : `Unknown option 'excludes'. Did you mean 'exclude'?` 
171+                 } ] ) ; 
172+ 
173+                 testFailure ( "can error when 'extends' is not a string" ,  "extends.json" ,  [ { 
174+                     code : 5024 , 
175+                     category : DiagnosticCategory . Error , 
176+                     messageText : `Compiler option 'extends' requires a value of type string.` 
177+                 } ] ) ; 
178+ 
179+                 testFailure ( "can error when 'extends' is neither relative nor rooted." ,  "extends2.json" ,  [ { 
180+                     code : 18001 , 
181+                     category : DiagnosticCategory . Error , 
182+                     messageText : `The path in an 'extends' options must be relative or rooted.` 
183+                 } ] ) ; 
184+             } ) ; 
185+         } ) ; 
186+     } ) ; 
187+ } 
0 commit comments