1namespace ts.projectSystem { 2 describe("unittests:: tsserver:: with project references and error reporting", () => { 3 const dependecyLocation = `${tscWatch.projectRoot}/dependency`; 4 const usageLocation = `${tscWatch.projectRoot}/usage`; 5 6 7 interface VerifyUsageAndDependency { 8 allFiles: readonly [File, File, File, File]; // dependencyTs, dependencyConfig, usageTs, usageConfig 9 usageDiagnostics(): GetErrDiagnostics; 10 dependencyDiagnostics(): GetErrDiagnostics; 11 12 } 13 function verifyUsageAndDependency({ allFiles, usageDiagnostics, dependencyDiagnostics }: VerifyUsageAndDependency) { 14 const [dependencyTs, dependencyConfig, usageTs, usageConfig] = allFiles; 15 function usageProjectDiagnostics(): GetErrForProjectDiagnostics { 16 return { 17 project: usageTs.path, 18 errors: [ 19 usageDiagnostics(), 20 emptyDiagnostics(dependencyTs) 21 ] 22 }; 23 } 24 25 function dependencyProjectDiagnostics(): GetErrForProjectDiagnostics { 26 return { 27 project: dependencyTs.path, 28 errors: [ 29 dependencyDiagnostics() 30 ] 31 }; 32 } 33 34 function usageConfigDiag(): server.ConfigFileDiagEvent["data"] { 35 return { 36 triggerFile: usageTs.path, 37 configFileName: usageConfig.path, 38 diagnostics: emptyArray 39 }; 40 } 41 42 function dependencyConfigDiag(): server.ConfigFileDiagEvent["data"] { 43 return { 44 triggerFile: dependencyTs.path, 45 configFileName: dependencyConfig.path, 46 diagnostics: emptyArray 47 }; 48 } 49 50 describe("when dependency project is not open", () => { 51 verifyGetErrScenario({ 52 allFiles: () => allFiles, 53 openFiles: () => [usageTs], 54 expectedGetErr: () => [ 55 usageDiagnostics() 56 ], 57 expectedGetErrForProject: () => [ 58 usageProjectDiagnostics(), 59 { 60 project: dependencyTs.path, 61 errors: [ 62 emptyDiagnostics(dependencyTs), 63 usageDiagnostics() 64 ] 65 } 66 ], 67 expectedSyncDiagnostics: () => [ 68 // Without project 69 usageDiagnostics(), 70 emptyDiagnostics(dependencyTs), 71 // With project 72 syncDiagnostics(usageDiagnostics(), usageConfig.path), 73 syncDiagnostics(emptyDiagnostics(dependencyTs), usageConfig.path), 74 ], 75 expectedConfigFileDiagEvents: () => [ 76 usageConfigDiag() 77 ], 78 }); 79 }); 80 81 describe("when the depedency file is open", () => { 82 verifyGetErrScenario({ 83 allFiles: () => allFiles, 84 openFiles: () => [usageTs, dependencyTs], 85 expectedGetErr: () => [ 86 usageDiagnostics(), 87 dependencyDiagnostics(), 88 ], 89 expectedGetErrForProject: () => [ 90 usageProjectDiagnostics(), 91 dependencyProjectDiagnostics() 92 ], 93 expectedSyncDiagnostics: () => [ 94 // Without project 95 usageDiagnostics(), 96 dependencyDiagnostics(), 97 // With project 98 syncDiagnostics(usageDiagnostics(), usageConfig.path), 99 syncDiagnostics(emptyDiagnostics(dependencyTs), usageConfig.path), 100 syncDiagnostics(dependencyDiagnostics(), dependencyConfig.path), 101 ], 102 expectedConfigFileDiagEvents: () => [ 103 usageConfigDiag(), 104 dependencyConfigDiag() 105 ], 106 }); 107 }); 108 } 109 110 describe("with module scenario", () => { 111 const dependencyTs: File = { 112 path: `${dependecyLocation}/fns.ts`, 113 content: `export function fn1() { } 114export function fn2() { } 115// Introduce error for fnErr import in main 116// export function fnErr() { } 117// Error in dependency ts file 118export let x: string = 10;` 119 }; 120 const dependencyConfig: File = { 121 path: `${dependecyLocation}/tsconfig.json`, 122 content: JSON.stringify({ compilerOptions: { composite: true, declarationDir: "../decls" } }) 123 }; 124 const usageTs: File = { 125 path: `${usageLocation}/usage.ts`, 126 content: `import { 127 fn1, 128 fn2, 129 fnErr 130} from '../decls/fns' 131fn1(); 132fn2(); 133fnErr(); 134` 135 }; 136 const usageConfig: File = { 137 path: `${usageLocation}/tsconfig.json`, 138 content: JSON.stringify({ 139 compilerOptions: { composite: true }, 140 references: [{ path: "../dependency" }] 141 }) 142 }; 143 function usageDiagnostics(): GetErrDiagnostics { 144 return { 145 file: usageTs, 146 syntax: emptyArray, 147 semantic: [ 148 createDiagnostic( 149 { line: 4, offset: 5 }, 150 { line: 4, offset: 10 }, 151 Diagnostics.Module_0_has_no_exported_member_1, 152 [`"../decls/fns"`, "fnErr"], 153 "error", 154 ) 155 ], 156 suggestion: emptyArray 157 }; 158 } 159 160 function dependencyDiagnostics(): GetErrDiagnostics { 161 return { 162 file: dependencyTs, 163 syntax: emptyArray, 164 semantic: [ 165 createDiagnostic( 166 { line: 6, offset: 12 }, 167 { line: 6, offset: 13 }, 168 Diagnostics.Type_0_is_not_assignable_to_type_1, 169 ["number", "string"], 170 "error", 171 ) 172 ], 173 suggestion: emptyArray 174 }; 175 } 176 177 verifyUsageAndDependency({ 178 allFiles: [dependencyTs, dependencyConfig, usageTs, usageConfig], 179 usageDiagnostics, 180 dependencyDiagnostics 181 }); 182 }); 183 184 describe("with non module --out", () => { 185 const dependencyTs: File = { 186 path: `${dependecyLocation}/fns.ts`, 187 content: `function fn1() { } 188function fn2() { } 189// Introduce error for fnErr import in main 190// function fnErr() { } 191// Error in dependency ts file 192let x: string = 10;` 193 }; 194 const dependencyConfig: File = { 195 path: `${dependecyLocation}/tsconfig.json`, 196 content: JSON.stringify({ compilerOptions: { composite: true, outFile: "../dependency.js" } }) 197 }; 198 const usageTs: File = { 199 path: `${usageLocation}/usage.ts`, 200 content: `fn1(); 201fn2(); 202fnErr(); 203` 204 }; 205 const usageConfig: File = { 206 path: `${usageLocation}/tsconfig.json`, 207 content: JSON.stringify({ 208 compilerOptions: { composite: true, outFile: "../usage.js" }, 209 references: [{ path: "../dependency" }] 210 }) 211 }; 212 function usageDiagnostics(): GetErrDiagnostics { 213 return { 214 file: usageTs, 215 syntax: emptyArray, 216 semantic: [ 217 createDiagnostic( 218 { line: 3, offset: 1 }, 219 { line: 3, offset: 6 }, 220 Diagnostics.Cannot_find_name_0, 221 ["fnErr"], 222 "error", 223 ) 224 ], 225 suggestion: emptyArray 226 }; 227 } 228 229 function dependencyDiagnostics(): GetErrDiagnostics { 230 return { 231 file: dependencyTs, 232 syntax: emptyArray, 233 semantic: [ 234 createDiagnostic( 235 { line: 6, offset: 5 }, 236 { line: 6, offset: 6 }, 237 Diagnostics.Type_0_is_not_assignable_to_type_1, 238 ["number", "string"], 239 "error", 240 ) 241 ], 242 suggestion: emptyArray 243 }; 244 } 245 246 verifyUsageAndDependency({ 247 allFiles: [dependencyTs, dependencyConfig, usageTs, usageConfig], 248 usageDiagnostics, 249 dependencyDiagnostics 250 }); 251 }); 252 }); 253} 254