1namespace ts { 2 describe("unittests:: config:: tsconfigParsingWatchOptions:: parseConfigFileTextToJson", () => { 3 function createParseConfigHost(additionalFiles?: vfs.FileSet) { 4 return new fakes.ParseConfigHost( 5 new vfs.FileSystem( 6 /*ignoreCase*/ false, 7 { 8 cwd: "/", 9 files: { "/": {}, "/a.ts": "", ...additionalFiles } 10 } 11 ) 12 ); 13 } 14 function getParsedCommandJson(json: object, additionalFiles?: vfs.FileSet, existingWatchOptions?: WatchOptions) { 15 return parseJsonConfigFileContent( 16 json, 17 createParseConfigHost(additionalFiles), 18 "/", 19 /*existingOptions*/ undefined, 20 "tsconfig.json", 21 /*resolutionStack*/ undefined, 22 /*extraFileExtensions*/ undefined, 23 /*extendedConfigCache*/ undefined, 24 existingWatchOptions, 25 ); 26 } 27 28 function getParsedCommandJsonNode(json: object, additionalFiles?: vfs.FileSet, existingWatchOptions?: WatchOptions) { 29 const parsed = parseJsonText("tsconfig.json", JSON.stringify(json)); 30 return parseJsonSourceFileConfigFileContent( 31 parsed, 32 createParseConfigHost(additionalFiles), 33 "/", 34 /*existingOptions*/ undefined, 35 "tsconfig.json", 36 /*resolutionStack*/ undefined, 37 /*extraFileExtensions*/ undefined, 38 /*extendedConfigCache*/ undefined, 39 existingWatchOptions, 40 ); 41 } 42 43 interface VerifyWatchOptions { 44 json: object; 45 expectedOptions: WatchOptions | undefined; 46 additionalFiles?: vfs.FileSet; 47 existingWatchOptions?: WatchOptions | undefined; 48 expectedErrors?: (sourceFile?: SourceFile) => Diagnostic[]; 49 } 50 51 function verifyWatchOptions(scenario: () => VerifyWatchOptions[]) { 52 it("with json api", () => { 53 for (const { json, expectedOptions, additionalFiles, existingWatchOptions, expectedErrors } of scenario()) { 54 const parsed = getParsedCommandJson(json, additionalFiles, existingWatchOptions); 55 assert.deepEqual(parsed.watchOptions, expectedOptions, `With ${JSON.stringify(json)}`); 56 if (length(parsed.errors)) { 57 assert.deepEqual(parsed.errors, expectedErrors?.()); 58 } 59 else { 60 assert.equal(0, length(expectedErrors?.()), `Expected no errors`); 61 } 62 } 63 }); 64 65 it("with json source file api", () => { 66 for (const { json, expectedOptions, additionalFiles, existingWatchOptions, expectedErrors } of scenario()) { 67 const parsed = getParsedCommandJsonNode(json, additionalFiles, existingWatchOptions); 68 assert.deepEqual(parsed.watchOptions, expectedOptions); 69 if (length(parsed.errors)) { 70 assert.deepEqual(parsed.errors, expectedErrors?.(parsed.options.configFile)); 71 } 72 else { 73 assert.equal(0, length(expectedErrors?.(parsed.options.configFile)), `Expected no errors`); 74 } 75 } 76 }); 77 } 78 79 describe("no watchOptions specified option", () => { 80 verifyWatchOptions(() => [{ 81 json: {}, 82 expectedOptions: undefined 83 }]); 84 }); 85 86 describe("empty watchOptions specified option", () => { 87 verifyWatchOptions(() => [{ 88 json: { watchOptions: {} }, 89 expectedOptions: undefined 90 }]); 91 }); 92 93 describe("extending config file", () => { 94 describe("when extending config file without watchOptions", () => { 95 verifyWatchOptions(() => [ 96 { 97 json: { 98 extends: "./base.json", 99 watchOptions: { watchFile: "UseFsEvents" } 100 }, 101 expectedOptions: { watchFile: WatchFileKind.UseFsEvents }, 102 additionalFiles: { "/base.json": "{}" } 103 }, 104 { 105 json: { extends: "./base.json", }, 106 expectedOptions: undefined, 107 additionalFiles: { "/base.json": "{}" } 108 } 109 ]); 110 }); 111 112 describe("when extending config file with watchOptions", () => { 113 verifyWatchOptions(() => [ 114 { 115 json: { 116 extends: "./base.json", 117 watchOptions: { 118 watchFile: "UseFsEvents", 119 } 120 }, 121 expectedOptions: { 122 watchFile: WatchFileKind.UseFsEvents, 123 watchDirectory: WatchDirectoryKind.FixedPollingInterval 124 }, 125 additionalFiles: { 126 "/base.json": JSON.stringify({ 127 watchOptions: { 128 watchFile: "UseFsEventsOnParentDirectory", 129 watchDirectory: "FixedPollingInterval" 130 } 131 }) 132 } 133 }, 134 { 135 json: { 136 extends: "./base.json", 137 }, 138 expectedOptions: { 139 watchFile: WatchFileKind.UseFsEventsOnParentDirectory, 140 watchDirectory: WatchDirectoryKind.FixedPollingInterval 141 }, 142 additionalFiles: { 143 "/base.json": JSON.stringify({ 144 watchOptions: { 145 watchFile: "UseFsEventsOnParentDirectory", 146 watchDirectory: "FixedPollingInterval" 147 } 148 }) 149 } 150 } 151 ]); 152 }); 153 }); 154 155 describe("different options", () => { 156 verifyWatchOptions(() => [ 157 { 158 json: { watchOptions: { watchFile: "UseFsEvents" } }, 159 expectedOptions: { watchFile: WatchFileKind.UseFsEvents } 160 }, 161 { 162 json: { watchOptions: { watchDirectory: "UseFsEvents" } }, 163 expectedOptions: { watchDirectory: WatchDirectoryKind.UseFsEvents } 164 }, 165 { 166 json: { watchOptions: { fallbackPolling: "DynamicPriority" } }, 167 expectedOptions: { fallbackPolling: PollingWatchKind.DynamicPriority } 168 }, 169 { 170 json: { watchOptions: { synchronousWatchDirectory: true } }, 171 expectedOptions: { synchronousWatchDirectory: true } 172 }, 173 { 174 json: { watchOptions: { excludeDirectories: ["**/temp"] } }, 175 expectedOptions: { excludeDirectories: ["/**/temp"] } 176 }, 177 { 178 json: { watchOptions: { excludeFiles: ["**/temp/*.ts"] } }, 179 expectedOptions: { excludeFiles: ["/**/temp/*.ts"] } 180 }, 181 { 182 json: { watchOptions: { excludeDirectories: ["**/../*"] } }, 183 expectedOptions: { excludeDirectories: [] }, 184 expectedErrors: sourceFile => [ 185 { 186 messageText: `File specification cannot contain a parent directory ('..') that appears after a recursive directory wildcard ('**'): '**/../*'.`, 187 category: Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0.category, 188 code: Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0.code, 189 file: sourceFile, 190 start: sourceFile && sourceFile.text.indexOf(`"**/../*"`), 191 length: sourceFile && `"**/../*"`.length, 192 reportsDeprecated: undefined, 193 reportsUnnecessary: undefined 194 } 195 ] 196 }, 197 { 198 json: { watchOptions: { excludeFiles: ["**/../*"] } }, 199 expectedOptions: { excludeFiles: [] }, 200 expectedErrors: sourceFile => [ 201 { 202 messageText: `File specification cannot contain a parent directory ('..') that appears after a recursive directory wildcard ('**'): '**/../*'.`, 203 category: Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0.category, 204 code: Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0.code, 205 file: sourceFile, 206 start: sourceFile && sourceFile.text.indexOf(`"**/../*"`), 207 length: sourceFile && `"**/../*"`.length, 208 reportsDeprecated: undefined, 209 reportsUnnecessary: undefined 210 } 211 ] 212 }, 213 ]); 214 }); 215 216 describe("watch options extending passed in watch options", () => { 217 verifyWatchOptions(() => [ 218 { 219 json: { watchOptions: { watchFile: "UseFsEvents" } }, 220 expectedOptions: { watchFile: WatchFileKind.UseFsEvents, watchDirectory: WatchDirectoryKind.FixedPollingInterval }, 221 existingWatchOptions: { watchDirectory: WatchDirectoryKind.FixedPollingInterval } 222 }, 223 { 224 json: {}, 225 expectedOptions: { watchDirectory: WatchDirectoryKind.FixedPollingInterval }, 226 existingWatchOptions: { watchDirectory: WatchDirectoryKind.FixedPollingInterval } 227 }, 228 ]); 229 }); 230 }); 231} 232