1namespace ts.tscWatch { 2 describe("unittests:: tsc-watch:: moduleResolution", () => { 3 verifyTscWatch({ 4 scenario: "moduleResolution", 5 subScenario: `watches for changes to package-json main fields`, 6 sys: () => createWatchedSystem([ 7 { 8 path: `${projectRoot}/packages/pkg1/package.json`, 9 content: JSON.stringify({ 10 name: "pkg1", 11 version: "1.0.0", 12 main: "build/index.js", 13 }) 14 }, 15 { 16 path: `${projectRoot}/packages/pkg1/index.ts`, 17 content: Utils.dedent` 18 import type { TheNum } from 'pkg2' 19 export const theNum: TheNum = 42;` 20 }, 21 { 22 path: `${projectRoot}/packages/pkg1/tsconfig.json`, 23 content: JSON.stringify({ 24 compilerOptions: { 25 outDir: "build", 26 }, 27 }) 28 }, 29 { 30 path: `${projectRoot}/packages/pkg2/build/const.d.ts`, 31 content: `export type TheNum = 42;` 32 }, 33 { 34 path: `${projectRoot}/packages/pkg2/build/index.d.ts`, 35 content: `export type { TheNum } from './const.js';` 36 }, 37 { 38 path: `${projectRoot}/packages/pkg2/build/other.d.ts`, 39 content: `export type TheStr = string;` 40 }, 41 { 42 path: `${projectRoot}/packages/pkg2/package.json`, 43 content: JSON.stringify({ 44 name: "pkg2", 45 version: "1.0.0", 46 main: "build/index.js", 47 }) 48 }, 49 { 50 path: `${projectRoot}/node_modules/pkg2`, 51 symLink: `${projectRoot}/packages/pkg2`, 52 }, 53 libFile 54 ], { currentDirectory: projectRoot }), 55 commandLineArgs: ["--project", "./packages/pkg1/tsconfig.json", "-w", "--traceResolution"], 56 changes: [ 57 { 58 caption: "reports import errors after change to package file", 59 change: sys => replaceFileText(sys, `${projectRoot}/packages/pkg2/package.json`, `index.js`, `other.js`), 60 timeouts: sys => { 61 sys.runQueuedTimeoutCallbacks(); // invalidates failed lookups 62 sys.runQueuedTimeoutCallbacks(); // actual update 63 }, 64 }, 65 { 66 caption: "removes those errors when a package file is changed back", 67 change: sys => replaceFileText(sys, `${projectRoot}/packages/pkg2/package.json`, `other.js`, `index.js`), 68 timeouts: sys => { 69 sys.runQueuedTimeoutCallbacks(); // invalidates failed lookups 70 sys.runQueuedTimeoutCallbacks(); // actual update 71 }, 72 }, 73 ] 74 }); 75 76 verifyTscWatch({ 77 scenario: "moduleResolution", 78 subScenario: "diagnostics from cache", 79 sys: () => createWatchedSystem([ 80 { 81 path: `${projectRoot}/tsconfig.json`, 82 content: JSON.stringify({ 83 compilerOptions: { 84 moduleResolution: "nodenext", 85 outDir: "./dist", 86 declaration: true, 87 declarationDir: "./types" 88 }, 89 }) 90 }, 91 { 92 path: `${projectRoot}/package.json`, 93 content: JSON.stringify({ 94 name: "@this/package", 95 type: "module", 96 exports: { 97 ".": { 98 default: "./dist/index.js", 99 types: "./types/index.d.ts" 100 } 101 } 102 }) 103 }, 104 { 105 path: `${projectRoot}/index.ts`, 106 content: Utils.dedent` 107 import * as me from "@this/package"; 108 me.thing() 109 export function thing(): void {} 110 ` 111 }, 112 libFile 113 ], { currentDirectory: projectRoot }), 114 commandLineArgs: ["-w", "--traceResolution"], 115 changes: emptyArray 116 }); 117 118 describe("package json file is edited", () => { 119 function getSys(packageFileContents: string) { 120 const configFile: File = { 121 path: `${projectRoot}/src/tsconfig.json`, 122 content: JSON.stringify({ 123 compilerOptions: { 124 target: "es2016", 125 module: "Node16", 126 outDir: "../out" 127 } 128 }) 129 }; 130 const packageFile: File = { 131 path: `${projectRoot}/package.json`, 132 content: packageFileContents 133 }; 134 const fileA: File = { 135 path: `${projectRoot}/src/fileA.ts`, 136 content: Utils.dedent` 137 import { foo } from "./fileB.mjs"; 138 foo(); 139 ` 140 }; 141 const fileB: File = { 142 path: `${projectRoot}/project/src/fileB.mts`, 143 content: Utils.dedent` 144 export function foo() { 145 } 146 ` 147 }; 148 return createWatchedSystem( 149 [configFile, fileA, fileB, packageFile, { ...libFile, path: "/a/lib/lib.es2016.full.d.ts" }], 150 { currentDirectory: projectRoot } 151 ); 152 } 153 verifyTscWatch({ 154 scenario: "moduleResolution", 155 subScenario: "package json file is edited", 156 commandLineArgs: ["--w", "--p", "src", "--extendedDiagnostics", "-traceResolution", "--explainFiles"], 157 sys: () => getSys(JSON.stringify({ name: "app", version: "1.0.0" })), 158 changes: [ 159 { 160 caption: "Modify package json file to add type module", 161 change: sys => sys.writeFile(`${projectRoot}/package.json`, JSON.stringify({ 162 name: "app", version: "1.0.0", type: "module", 163 })), 164 timeouts: host => { 165 host.runQueuedTimeoutCallbacks(); // Failed lookup updates 166 host.runQueuedTimeoutCallbacks(); // Actual update 167 }, 168 }, 169 { 170 caption: "Modify package.json file to remove type module", 171 change: sys => sys.writeFile(`${projectRoot}/package.json`, JSON.stringify({ name: "app", version: "1.0.0" })), 172 timeouts: host => { 173 host.runQueuedTimeoutCallbacks(); // Failed lookup updates 174 host.runQueuedTimeoutCallbacks(); // Actual update 175 }, 176 }, 177 { 178 caption: "Delete package.json", 179 change: sys => sys.deleteFile(`${projectRoot}/package.json`), 180 timeouts: host => { 181 host.runQueuedTimeoutCallbacks(); // Failed lookup updates 182 host.runQueuedTimeoutCallbacks(); // Actual update 183 }, 184 }, 185 { 186 caption: "Modify package json file to add type module", 187 change: sys => sys.writeFile(`${projectRoot}/package.json`, JSON.stringify({ 188 name: "app", version: "1.0.0", type: "module", 189 })), 190 timeouts: host => { 191 host.runQueuedTimeoutCallbacks(); // Failed lookup updates 192 host.runQueuedTimeoutCallbacks(); // Actual update 193 }, 194 }, 195 { 196 caption: "Delete package.json", 197 change: sys => sys.deleteFile(`${projectRoot}/package.json`), 198 timeouts: host => { 199 host.runQueuedTimeoutCallbacks(); // Failed lookup updates 200 host.runQueuedTimeoutCallbacks(); // Actual update 201 }, 202 }, 203 ], 204 }); 205 206 verifyTscWatch({ 207 scenario: "moduleResolution", 208 subScenario: "package json file is edited when package json with type module exists", 209 commandLineArgs: ["--w", "--p", "src", "--extendedDiagnostics", "-traceResolution", "--explainFiles"], 210 sys: () => getSys(JSON.stringify({ 211 name: "app", version: "1.0.0", type: "module", 212 })), 213 changes: [ 214 { 215 caption: "Modify package.json file to remove type module", 216 change: sys => sys.writeFile(`${projectRoot}/package.json`, JSON.stringify({ name: "app", version: "1.0.0" })), 217 timeouts: host => { 218 host.runQueuedTimeoutCallbacks(); // Failed lookup updates 219 host.runQueuedTimeoutCallbacks(); // Actual update 220 }, 221 }, 222 { 223 caption: "Modify package json file to add type module", 224 change: sys => sys.writeFile(`${projectRoot}/package.json`, JSON.stringify({ 225 name: "app", version: "1.0.0", type: "module", 226 })), 227 timeouts: host => { 228 host.runQueuedTimeoutCallbacks(); // Failed lookup updates 229 host.runQueuedTimeoutCallbacks(); // Actual update 230 }, 231 }, 232 { 233 caption: "Delete package.json", 234 change: sys => sys.deleteFile(`${projectRoot}/package.json`), 235 timeouts: host => { 236 host.runQueuedTimeoutCallbacks(); // Failed lookup updates 237 host.runQueuedTimeoutCallbacks(); // Actual update 238 }, 239 }, 240 { 241 caption: "Modify package json file to without type module", 242 change: sys => sys.writeFile(`${projectRoot}/package.json`, JSON.stringify({ name: "app", version: "1.0.0" })), 243 timeouts: host => { 244 host.runQueuedTimeoutCallbacks(); // Failed lookup updates 245 host.runQueuedTimeoutCallbacks(); // Actual update 246 }, 247 }, 248 { 249 caption: "Delete package.json", 250 change: sys => sys.deleteFile(`${projectRoot}/package.json`), 251 timeouts: host => { 252 host.runQueuedTimeoutCallbacks(); // Failed lookup updates 253 host.runQueuedTimeoutCallbacks(); // Actual update 254 }, 255 }, 256 ], 257 }); 258 }); 259 }); 260}