mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Enable '--strictNullChecks' (#22088)
* Enable '--strictNullChecks' * Fix API baselines * Make sys.getEnvironmentVariable non-nullable * make properties optional instead of using `| undefined` in thier type * reportDiagnostics should be required * Declare firstAccessor as non-nullable * Make `some` a type guard * Fix `getEnvironmentVariable` definition in tests * Pretend transformFlags are always defined * Fix one more use of sys.getEnvironmentVariable * `requiredResponse` accepts undefined, remove assertions * Mark optional properties as optional instead of using `| undefined` * Mark optional properties as optional instead of using ` | undefined` * Remove unnecessary null assertions * Put the bang on the declaration instead of every use * Make `createMapFromTemplate` require a parameter * Mark `EmitResult.emittedFiles` and `EmitResult.sourceMaps` as optional * Plumb through undefined in emitLsit and EmitExpressionList * `ElementAccessExpression.argumentExpression` can not be `undefined` * Add overloads for `writeTokenText` * Make `shouldWriteSeparatingLineTerminator` argument non-nullable * Make `synthesizedNodeStartsOnNewLine` argument required * `PropertyAssignment.initializer` cannot be undefined * Use one `!` at declaration site instead of on every use site * Capture host in a constant and avoid null assertions * Remove few more unused assertions * Update baselines * Use parameter defaults * Update baselines * Fix lint * Make Symbol#valueDeclaration and Symbol#declarations non-optional to reduce assertions * Make Node#symbol and Type#symbol non-optional to reduce assertions * Make `flags` non-nullable to reduce assertions * Convert some asserts to type guards * Make `isNonLocalAlias` a type guard * Add overload for `getSymbolOfNode` for `Declaration` * Some more `getSymbolOfNode` changes * Push undefined suppression into `typeToTypeNodeHelper` * `NodeBuilderContext.tracker` is never `undefined` * use `Debug.assertDefined` * Remove unnecessary tag * Mark `LiteralType.freshType` and `LiteralTupe.regularType` as required
This commit is contained in:
@@ -182,8 +182,8 @@ namespace compiler {
|
||||
}
|
||||
|
||||
public getSourceMapRecord(): string | undefined {
|
||||
if (this.result.sourceMaps && this.result.sourceMaps.length > 0) {
|
||||
return Harness.SourceMapRecorder.getSourceMapRecord(this.result.sourceMaps, this.program, Array.from(this.js.values()), Array.from(this.dts.values()));
|
||||
if (this.result!.sourceMaps && this.result!.sourceMaps!.length > 0) {
|
||||
return Harness.SourceMapRecorder.getSourceMapRecord(this.result!.sourceMaps!, this.program!, Array.from(this.js.values()), Array.from(this.dts.values()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ class CompilerBaselineRunner extends RunnerBase {
|
||||
private runSuite(fileName: string, test?: CompilerFileBasedTest, configuration?: Harness.FileBasedTestConfiguration) {
|
||||
// Mocha holds onto the closure environment of the describe callback even after the test is done.
|
||||
// Everything declared here should be cleared out in the "after" callback.
|
||||
let compilerTest: CompilerTest | undefined;
|
||||
let compilerTest!: CompilerTest;
|
||||
before(() => { compilerTest = new CompilerTest(fileName, test && test.payload, configuration); });
|
||||
it(`Correct errors for ${fileName}`, () => { compilerTest.verifyDiagnostics(); });
|
||||
it(`Correct module resolution tracing for ${fileName}`, () => { compilerTest.verifyModuleResolution(); });
|
||||
@@ -89,7 +89,7 @@ class CompilerBaselineRunner extends RunnerBase {
|
||||
it(`Correct JS output for ${fileName}`, () => { if (this.emit) compilerTest.verifyJavaScriptOutput(); });
|
||||
it(`Correct Sourcemap output for ${fileName}`, () => { compilerTest.verifySourceMapOutput(); });
|
||||
it(`Correct type/symbol baselines for ${fileName}`, () => { compilerTest.verifyTypesAndSymbols(); });
|
||||
after(() => { compilerTest = undefined; });
|
||||
after(() => { compilerTest = undefined!; });
|
||||
}
|
||||
|
||||
private parseOptions() {
|
||||
@@ -131,7 +131,7 @@ class CompilerTest {
|
||||
const rootDir = fileName.indexOf("conformance") === -1 ? "tests/cases/compiler/" : ts.getDirectoryPath(fileName) + "/";
|
||||
|
||||
if (testCaseContent === undefined) {
|
||||
testCaseContent = Harness.TestCaseParser.makeUnitsFromTest(Harness.IO.readFile(fileName), fileName, rootDir);
|
||||
testCaseContent = Harness.TestCaseParser.makeUnitsFromTest(Harness.IO.readFile(fileName)!, fileName, rootDir);
|
||||
}
|
||||
|
||||
if (configurationOverrides) {
|
||||
@@ -140,13 +140,13 @@ class CompilerTest {
|
||||
|
||||
const units = testCaseContent.testUnitData;
|
||||
this.harnessSettings = testCaseContent.settings;
|
||||
let tsConfigOptions: ts.CompilerOptions;
|
||||
let tsConfigOptions: ts.CompilerOptions | undefined;
|
||||
this.tsConfigFiles = [];
|
||||
if (testCaseContent.tsConfig) {
|
||||
assert.equal(testCaseContent.tsConfig.fileNames.length, 0, `list of files in tsconfig is not currently supported`);
|
||||
|
||||
tsConfigOptions = ts.cloneCompilerOptions(testCaseContent.tsConfig.options);
|
||||
this.tsConfigFiles.push(this.createHarnessTestFile(testCaseContent.tsConfigFileUnitData, rootDir, ts.combinePaths(rootDir, tsConfigOptions.configFilePath)));
|
||||
this.tsConfigFiles.push(this.createHarnessTestFile(testCaseContent.tsConfigFileUnitData!, rootDir, ts.combinePaths(rootDir, tsConfigOptions.configFilePath!)));
|
||||
}
|
||||
else {
|
||||
const baseUrl = this.harnessSettings.baseUrl;
|
||||
@@ -156,7 +156,7 @@ class CompilerTest {
|
||||
}
|
||||
|
||||
this.lastUnit = units[units.length - 1];
|
||||
this.hasNonDtsFiles = ts.forEach(units, unit => !ts.fileExtensionIs(unit.name, ts.Extension.Dts));
|
||||
this.hasNonDtsFiles = units.some(unit => !ts.fileExtensionIs(unit.name, ts.Extension.Dts));
|
||||
// We need to assemble the list of input files for the compiler and other related files on the 'filesystem' (ie in a multi-file test)
|
||||
// If the last file in a test uses require or a triple slash reference we'll assume all other files will be brought in via references,
|
||||
// otherwise, assume all files are just meant to be in the same compilation session without explicit references to one another.
|
||||
@@ -179,7 +179,7 @@ class CompilerTest {
|
||||
|
||||
if (tsConfigOptions && tsConfigOptions.configFilePath !== undefined) {
|
||||
tsConfigOptions.configFilePath = ts.combinePaths(rootDir, tsConfigOptions.configFilePath);
|
||||
tsConfigOptions.configFile.fileName = tsConfigOptions.configFilePath;
|
||||
tsConfigOptions.configFile!.fileName = tsConfigOptions.configFilePath;
|
||||
}
|
||||
|
||||
this.result = Harness.Compiler.compileFiles(
|
||||
@@ -194,7 +194,7 @@ class CompilerTest {
|
||||
|
||||
public static getConfigurations(file: string): CompilerFileBasedTest {
|
||||
// also see `parseCompilerTestConfigurations` in tests/webTestServer.ts
|
||||
const content = Harness.IO.readFile(file);
|
||||
const content = Harness.IO.readFile(file)!;
|
||||
const rootDir = file.indexOf("conformance") === -1 ? "tests/cases/compiler/" : ts.getDirectoryPath(file) + "/";
|
||||
const payload = Harness.TestCaseParser.makeUnitsFromTest(content, file, rootDir);
|
||||
const settings = Harness.TestCaseParser.extractCompilerSettings(content);
|
||||
@@ -222,7 +222,7 @@ class CompilerTest {
|
||||
public verifySourceMapRecord() {
|
||||
if (this.options.sourceMap || this.options.inlineSourceMap || this.options.declarationMap) {
|
||||
Harness.Baseline.runBaseline(this.justName.replace(/\.tsx?$/, ".sourcemap.txt"), () => {
|
||||
const record = utils.removeTestPathPrefixes(this.result.getSourceMapRecord());
|
||||
const record = utils.removeTestPathPrefixes(this.result.getSourceMapRecord()!);
|
||||
if ((this.options.noEmitOnError && this.result.diagnostics.length !== 0) || record === undefined) {
|
||||
// Because of the noEmitOnError option no files are created. We need to return null because baselining isn't required.
|
||||
/* tslint:disable:no-null-keyword */
|
||||
@@ -263,8 +263,8 @@ class CompilerTest {
|
||||
|
||||
Harness.Compiler.doTypeAndSymbolBaseline(
|
||||
this.justName,
|
||||
this.result.program,
|
||||
this.toBeCompiled.concat(this.otherFiles).filter(file => !!this.result.program.getSourceFile(file.unitName)));
|
||||
this.result.program!,
|
||||
this.toBeCompiled.concat(this.otherFiles).filter(file => !!this.result.program!.getSourceFile(file.unitName)));
|
||||
}
|
||||
|
||||
private makeUnitName(name: string, root: string) {
|
||||
|
||||
@@ -151,9 +151,9 @@ namespace documents {
|
||||
return match ? new SourceMap(/*mapFile*/ undefined, new Buffer(match[1], "base64").toString("utf8")) : undefined;
|
||||
}
|
||||
|
||||
public static fromSource(text: string) {
|
||||
public static fromSource(text: string): SourceMap | undefined {
|
||||
const url = this.getUrl(text);
|
||||
return url && this.fromUrl(url);
|
||||
return url === undefined ? undefined : this.fromUrl(url);
|
||||
}
|
||||
|
||||
public getMappingsForEmittedLine(emittedLine: number): ReadonlyArray<Mapping> | undefined {
|
||||
|
||||
@@ -16,7 +16,7 @@ interface UserConfig {
|
||||
|
||||
abstract class ExternalCompileRunnerBase extends RunnerBase {
|
||||
abstract testDir: string;
|
||||
abstract report(result: ExecResult, cwd: string): string;
|
||||
abstract report(result: ExecResult, cwd: string): string | null;
|
||||
enumerateTestFiles() {
|
||||
return Harness.IO.getDirectories(this.testDir);
|
||||
}
|
||||
@@ -48,7 +48,7 @@ abstract class ExternalCompileRunnerBase extends RunnerBase {
|
||||
let cwd = path.join(Harness.IO.getWorkspaceRoot(), cls.testDir, directoryName);
|
||||
const originalCwd = cwd;
|
||||
const stdio = isWorker ? "pipe" : "inherit";
|
||||
let types: string[];
|
||||
let types: string[] | undefined;
|
||||
if (fs.existsSync(path.join(cwd, "test.json"))) {
|
||||
const submoduleDir = path.join(cwd, directoryName);
|
||||
const reset = cp.spawnSync("git", ["reset", "HEAD", "--hard"], { cwd: submoduleDir, timeout, shell: true, stdio });
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace fakes {
|
||||
public readonly output: string[] = [];
|
||||
public readonly newLine: string;
|
||||
public readonly useCaseSensitiveFileNames: boolean;
|
||||
public exitCode: number;
|
||||
public exitCode: number | undefined;
|
||||
|
||||
private readonly _executingFilePath: string | undefined;
|
||||
private readonly _env: Record<string, string> | undefined;
|
||||
@@ -128,7 +128,7 @@ namespace fakes {
|
||||
|
||||
public getModifiedTime(path: string) {
|
||||
const stats = this._getStats(path);
|
||||
return stats ? stats.mtime : undefined;
|
||||
return stats ? stats.mtime : undefined!; // TODO: GH#18217
|
||||
}
|
||||
|
||||
public createHash(data: string): string {
|
||||
@@ -144,8 +144,8 @@ namespace fakes {
|
||||
}
|
||||
}
|
||||
|
||||
public getEnvironmentVariable(name: string): string | undefined {
|
||||
return this._env && this._env[name];
|
||||
public getEnvironmentVariable(name: string): string {
|
||||
return (this._env && this._env[name])!; // TODO: GH#18217
|
||||
}
|
||||
|
||||
private _getStats(path: string) {
|
||||
@@ -275,7 +275,7 @@ namespace fakes {
|
||||
this._outputsMap.set(document.file, this.outputs.length);
|
||||
this.outputs.push(document);
|
||||
}
|
||||
this.outputs[this._outputsMap.get(document.file)] = document;
|
||||
this.outputs[this._outputsMap.get(document.file)!] = document;
|
||||
}
|
||||
|
||||
public trace(s: string): void {
|
||||
@@ -332,7 +332,7 @@ namespace fakes {
|
||||
let fs = this.vfs;
|
||||
while (fs.shadowRoot) {
|
||||
try {
|
||||
const shadowRootStats = fs.shadowRoot.existsSync(canonicalFileName) && fs.shadowRoot.statSync(canonicalFileName);
|
||||
const shadowRootStats = fs.shadowRoot.existsSync(canonicalFileName) ? fs.shadowRoot.statSync(canonicalFileName) : undefined!; // TODO: GH#18217
|
||||
if (shadowRootStats.dev !== stats.dev ||
|
||||
shadowRootStats.ino !== stats.ino ||
|
||||
shadowRootStats.mtimeMs !== stats.mtimeMs) {
|
||||
|
||||
+117
-117
@@ -184,7 +184,7 @@ namespace FourSlash {
|
||||
|
||||
private inputFiles = ts.createMap<string>(); // Map between inputFile's fileName and its content for easily looking up when resolving references
|
||||
|
||||
private static getDisplayPartsJson(displayParts: ts.SymbolDisplayPart[]) {
|
||||
private static getDisplayPartsJson(displayParts: ts.SymbolDisplayPart[] | undefined) {
|
||||
let result = "";
|
||||
ts.forEach(displayParts, part => {
|
||||
if (result) {
|
||||
@@ -204,7 +204,7 @@ namespace FourSlash {
|
||||
|
||||
// Add input file which has matched file name with the given reference-file path.
|
||||
// This is necessary when resolveReference flag is specified
|
||||
private addMatchedInputFile(referenceFilePath: string, extensions: ReadonlyArray<string>) {
|
||||
private addMatchedInputFile(referenceFilePath: string, extensions: ReadonlyArray<string> | undefined) {
|
||||
const inputFiles = this.inputFiles;
|
||||
const languageServiceAdapterHost = this.languageServiceAdapterHost;
|
||||
const didAdd = tryAdd(referenceFilePath);
|
||||
@@ -243,16 +243,16 @@ namespace FourSlash {
|
||||
compilationOptions.skipDefaultLibCheck = true;
|
||||
|
||||
// Initialize the language service with all the scripts
|
||||
let startResolveFileRef: FourSlashFile;
|
||||
let startResolveFileRef: FourSlashFile | undefined;
|
||||
|
||||
let configFileName: string;
|
||||
let configFileName: string | undefined;
|
||||
for (const file of testData.files) {
|
||||
// Create map between fileName and its content for easily looking up when resolveReference flag is specified
|
||||
this.inputFiles.set(file.fileName, file.content);
|
||||
if (isConfig(file)) {
|
||||
const configJson = ts.parseConfigFileTextToJson(file.fileName, file.content);
|
||||
if (configJson.config === undefined) {
|
||||
throw new Error(`Failed to parse test ${file.fileName}: ${configJson.error.messageText}`);
|
||||
throw new Error(`Failed to parse test ${file.fileName}: ${configJson.error!.messageText}`);
|
||||
}
|
||||
|
||||
// Extend our existing compiler options so that we can also support tsconfig only options
|
||||
@@ -280,12 +280,12 @@ namespace FourSlash {
|
||||
const baseDir = ts.normalizePath(ts.getDirectoryPath(configFileName));
|
||||
const files: vfs.FileSet = { [baseDir]: {} };
|
||||
this.inputFiles.forEach((data, path) => {
|
||||
const scriptInfo = new Harness.LanguageService.ScriptInfo(path, undefined, /*isRootFile*/ false);
|
||||
const scriptInfo = new Harness.LanguageService.ScriptInfo(path, undefined!, /*isRootFile*/ false); // TODO: GH#18217
|
||||
files[path] = new vfs.File(data, { meta: { scriptInfo } });
|
||||
});
|
||||
const fs = new vfs.FileSystem(/*ignoreCase*/ true, { cwd: baseDir, files });
|
||||
const host = new fakes.ParseConfigHost(fs);
|
||||
const jsonSourceFile = ts.parseJsonText(configFileName, this.inputFiles.get(configFileName));
|
||||
const jsonSourceFile = ts.parseJsonText(configFileName, this.inputFiles.get(configFileName)!);
|
||||
compilationOptions = ts.parseJsonSourceFileConfigFileContent(jsonSourceFile, host, baseDir, compilationOptions, configFileName).options;
|
||||
}
|
||||
|
||||
@@ -323,7 +323,7 @@ namespace FourSlash {
|
||||
// Check if no-default-lib flag is false and if so add default library
|
||||
if (!resolvedResult.isLibFile) {
|
||||
this.languageServiceAdapterHost.addScript(Harness.Compiler.defaultLibFileName,
|
||||
Harness.Compiler.getDefaultLibrarySourceFile().text, /*isRootFile*/ false);
|
||||
Harness.Compiler.getDefaultLibrarySourceFile()!.text, /*isRootFile*/ false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -335,7 +335,7 @@ namespace FourSlash {
|
||||
});
|
||||
if (!compilationOptions.noLib) {
|
||||
this.languageServiceAdapterHost.addScript(Harness.Compiler.defaultLibFileName,
|
||||
Harness.Compiler.getDefaultLibrarySourceFile().text, /*isRootFile*/ false);
|
||||
Harness.Compiler.getDefaultLibrarySourceFile()!.text, /*isRootFile*/ false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,7 +393,7 @@ namespace FourSlash {
|
||||
(...args) => args.join("|,|")
|
||||
);
|
||||
proxy[key] = (...args: any[]) => memo(
|
||||
target.languageServiceAdapterHost.getScriptInfo(target.activeFile.fileName).version,
|
||||
target.languageServiceAdapterHost.getScriptInfo(target.activeFile.fileName)!.version,
|
||||
target.activeFile.fileName,
|
||||
target.currentCaretPosition,
|
||||
target.selectionEnd,
|
||||
@@ -406,7 +406,7 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
private getFileContent(fileName: string): string {
|
||||
const script = this.languageServiceAdapterHost.getScriptInfo(fileName);
|
||||
const script = this.languageServiceAdapterHost.getScriptInfo(fileName)!;
|
||||
return script.content;
|
||||
}
|
||||
|
||||
@@ -548,9 +548,9 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
private anyErrorInRange(predicate: (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) => boolean, startMarker: Marker, endMarker?: Marker): boolean {
|
||||
private anyErrorInRange(predicate: (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number | undefined) => boolean, startMarker: Marker, endMarker?: Marker): boolean {
|
||||
return this.getDiagnostics(startMarker.fileName).some(({ start, length }) =>
|
||||
predicate(start, start + length, startMarker.position, endMarker === undefined ? undefined : endMarker.position));
|
||||
predicate(start!, start! + length!, startMarker.position, endMarker === undefined ? undefined : endMarker.position)); // TODO: GH#18217
|
||||
}
|
||||
|
||||
private printErrorLog(expectErrors: boolean, errors: ts.Diagnostic[]) {
|
||||
@@ -562,12 +562,12 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
for (const { start, length, messageText, file } of errors) {
|
||||
Harness.IO.log(" " + this.formatRange(file, start, length) +
|
||||
Harness.IO.log(" " + this.formatRange(file, start!, length!) + // TODO: GH#18217
|
||||
", message: " + ts.flattenDiagnosticMessageText(messageText, Harness.IO.newLine()) + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
private formatRange(file: ts.SourceFile, start: number, length: number) {
|
||||
private formatRange(file: ts.SourceFile | undefined, start: number, length: number) {
|
||||
if (file) {
|
||||
return `from: ${this.formatLineAndCharacterOfPosition(file, start)}, to: ${this.formatLineAndCharacterOfPosition(file, start + length)}`;
|
||||
}
|
||||
@@ -597,7 +597,7 @@ namespace FourSlash {
|
||||
if (errors.length) {
|
||||
this.printErrorLog(/*expectErrors*/ false, errors);
|
||||
const error = errors[0];
|
||||
this.raiseError(`Found an error: ${this.formatPosition(error.file, error.start)}: ${error.messageText}`);
|
||||
this.raiseError(`Found an error: ${this.formatPosition(error.file!, error.start!)}: ${error.messageText}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -635,11 +635,11 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
private getGoToDefinition(): ts.DefinitionInfo[] {
|
||||
return this.languageService.getDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition);
|
||||
return this.languageService.getDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition)!;
|
||||
}
|
||||
|
||||
private getGoToDefinitionAndBoundSpan(): ts.DefinitionInfoAndBoundSpan {
|
||||
return this.languageService.getDefinitionAndBoundSpan(this.activeFile.fileName, this.currentCaretPosition);
|
||||
return this.languageService.getDefinitionAndBoundSpan(this.activeFile.fileName, this.currentCaretPosition)!;
|
||||
}
|
||||
|
||||
public verifyGoToType(arg0: any, endMarkerNames?: ArrayOrSingle<string>) {
|
||||
@@ -694,9 +694,9 @@ namespace FourSlash {
|
||||
testName = "goToDefinitions";
|
||||
}
|
||||
else {
|
||||
this.verifyDefinitionTextSpan(defs, startMarkerName);
|
||||
this.verifyDefinitionTextSpan(defs, startMarkerName!);
|
||||
|
||||
definitions = defs.definitions;
|
||||
definitions = defs.definitions!; // TODO: GH#18217
|
||||
testName = "goToDefinitionsAndBoundSpan";
|
||||
}
|
||||
|
||||
@@ -713,7 +713,7 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
private verifyDefinitionTextSpan(defs: ts.DefinitionInfoAndBoundSpan, startMarkerName: string) {
|
||||
const range = this.testData.ranges.find(range => this.markerName(range.marker) === startMarkerName);
|
||||
const range = this.testData.ranges.find(range => this.markerName(range.marker!) === startMarkerName);
|
||||
|
||||
if (!range && !defs.textSpan) {
|
||||
return;
|
||||
@@ -791,7 +791,7 @@ namespace FourSlash {
|
||||
return;
|
||||
}
|
||||
|
||||
const entries = this.getCompletionListAtCaret().entries;
|
||||
const entries = this.getCompletionListAtCaret()!.entries;
|
||||
assert.isTrue(items.length <= entries.length, `Amount of expected items in completion list [ ${items.length} ] is greater than actual number of items in list [ ${entries.length} ]`);
|
||||
ts.zipWith(entries, items, (entry, item) => {
|
||||
assert.equal(entry.name, item, `Unexpected item in completion list`);
|
||||
@@ -799,7 +799,7 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
public noItemsWithSameNameButDifferentKind(): void {
|
||||
const completions = this.getCompletionListAtCaret();
|
||||
const completions = this.getCompletionListAtCaret()!;
|
||||
const uniqueItems = ts.createMap<string>();
|
||||
for (const item of completions.entries) {
|
||||
const uniqueItem = uniqueItems.get(item.name);
|
||||
@@ -854,7 +854,7 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
private verifyCompletionsWorker(options: FourSlashInterface.VerifyCompletionsOptions): void {
|
||||
const actualCompletions = this.getCompletionListAtCaret({ ...options.preferences, triggerCharacter: options.triggerCharacter });
|
||||
const actualCompletions = this.getCompletionListAtCaret({ ...options.preferences, triggerCharacter: options.triggerCharacter })!;
|
||||
if (!actualCompletions) {
|
||||
if (options.exact === undefined) return;
|
||||
this.raiseError(`No completions at position '${this.currentCaretPosition}'.`);
|
||||
@@ -877,7 +877,7 @@ namespace FourSlash {
|
||||
|
||||
if ("exact" in options) {
|
||||
ts.Debug.assert(!("includes" in options) && !("excludes" in options));
|
||||
if (options.exact === undefined) this.raiseError("Expected no completions");
|
||||
if (options.exact === undefined) throw this.raiseError("Expected no completions");
|
||||
this.verifyCompletionsAreExactly(actualCompletions.entries, toArray(options.exact));
|
||||
}
|
||||
else {
|
||||
@@ -885,7 +885,7 @@ namespace FourSlash {
|
||||
for (const include of toArray(options.includes)) {
|
||||
const name = typeof include === "string" ? include : include.name;
|
||||
const found = actualByName.get(name);
|
||||
if (!found) this.raiseError(`No completion ${name} found`);
|
||||
if (!found) throw this.raiseError(`No completion ${name} found`);
|
||||
this.verifyCompletionEntry(found, include);
|
||||
}
|
||||
}
|
||||
@@ -929,7 +929,7 @@ namespace FourSlash {
|
||||
assert.equal(actual.isRecommended, isRecommended);
|
||||
|
||||
if (text) {
|
||||
const actualDetails = this.getCompletionEntryDetails(actual.name, actual.source);
|
||||
const actualDetails = this.getCompletionEntryDetails(actual.name, actual.source)!;
|
||||
assert.equal(ts.displayPartsToString(actualDetails.displayParts), text);
|
||||
assert.equal(ts.displayPartsToString(actualDetails.documentation), documentation || "");
|
||||
// TODO: GH#23587
|
||||
@@ -962,8 +962,7 @@ namespace FourSlash {
|
||||
exact: expected,
|
||||
isNewIdentifierLocation: options && options.isNewIdentifierLocation,
|
||||
preferences: options,
|
||||
// TODO: GH#20090
|
||||
triggerCharacter: (options && options.triggerCharacter) as ts.CompletionsTriggerCharacter | undefined,
|
||||
triggerCharacter: options && options.triggerCharacter,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -989,7 +988,7 @@ namespace FourSlash {
|
||||
* @param spanIndex the index of the range that the completion item's replacement text span should match
|
||||
*/
|
||||
public verifyCompletionListDoesNotContain(entryId: ts.Completions.CompletionEntryIdentifier, expectedText?: string, expectedDocumentation?: string, expectedKind?: string | { kind?: string, kindModifiers?: string }, spanIndex?: number, options?: FourSlashInterface.CompletionsAtOptions) {
|
||||
let replacementSpan: ts.TextSpan;
|
||||
let replacementSpan: ts.TextSpan | undefined;
|
||||
if (spanIndex !== undefined) {
|
||||
replacementSpan = this.getTextSpanForRangeAtIndex(spanIndex);
|
||||
}
|
||||
@@ -1022,7 +1021,7 @@ namespace FourSlash {
|
||||
// then these symbols must meet the criterion for Not supposed to be in the list. So we
|
||||
// raise an error
|
||||
let error = `Completion list did contain '${JSON.stringify(entryId)}\'.`;
|
||||
const details = this.getCompletionEntryDetails(filterCompletions[0].name);
|
||||
const details = this.getCompletionEntryDetails(filterCompletions[0].name)!;
|
||||
if (expectedText) {
|
||||
error += "Expected text: " + expectedText + " to equal: " + ts.displayPartsToString(details.displayParts) + ".";
|
||||
}
|
||||
@@ -1045,7 +1044,7 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
public verifyCompletionEntryDetails(entryName: string, expectedText: string, expectedDocumentation?: string, kind?: string, tags?: ts.JSDocTagInfo[]) {
|
||||
const details = this.getCompletionEntryDetails(entryName);
|
||||
const details = this.getCompletionEntryDetails(entryName)!;
|
||||
|
||||
assert(details, "no completion entry available");
|
||||
|
||||
@@ -1060,8 +1059,8 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
if (tags !== undefined) {
|
||||
assert.equal(details.tags.length, tags.length, this.messageAtLastKnownMarker("QuickInfo tags"));
|
||||
ts.zipWith(tags, details.tags, (expectedTag, actualTag) => {
|
||||
assert.equal(details.tags!.length, tags.length, this.messageAtLastKnownMarker("QuickInfo tags"));
|
||||
ts.zipWith(tags, details.tags!, (expectedTag, actualTag) => {
|
||||
assert.equal(actualTag.name, expectedTag.name);
|
||||
assert.equal(actualTag.text, expectedTag.text, this.messageAtLastKnownMarker("QuickInfo tag " + actualTag.name));
|
||||
});
|
||||
@@ -1074,7 +1073,7 @@ namespace FourSlash {
|
||||
private _checker: ts.TypeChecker;
|
||||
|
||||
private getProgram(): ts.Program {
|
||||
return this._program || (this._program = this.languageService.getProgram());
|
||||
return this._program || (this._program = this.languageService.getProgram()!); // TODO: GH#18217
|
||||
}
|
||||
|
||||
private getChecker() {
|
||||
@@ -1122,7 +1121,7 @@ namespace FourSlash {
|
||||
|
||||
public verifySymbolAtLocation(startRange: Range, declarationRanges: Range[]): void {
|
||||
const node = this.goToAndGetNode(startRange);
|
||||
const symbol = this.getChecker().getSymbolAtLocation(node);
|
||||
const symbol = this.getChecker().getSymbolAtLocation(node)!;
|
||||
if (!symbol) {
|
||||
this.raiseError("Could not get symbol at location");
|
||||
}
|
||||
@@ -1153,14 +1152,14 @@ namespace FourSlash {
|
||||
const startFile = this.activeFile.fileName;
|
||||
for (const fileName of files) {
|
||||
const searchFileNames = startFile === fileName ? [startFile] : [startFile, fileName];
|
||||
const highlights = this.getDocumentHighlightsAtCurrentPosition(searchFileNames);
|
||||
const highlights = this.getDocumentHighlightsAtCurrentPosition(searchFileNames)!;
|
||||
if (!highlights.every(dh => ts.contains(searchFileNames, dh.fileName))) {
|
||||
this.raiseError(`When asking for document highlights only in files ${searchFileNames}, got document highlights in ${unique(highlights, dh => dh.fileName)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public verifyReferenceGroups(starts: ArrayOrSingle<string> | ArrayOrSingle<Range>, parts: ReadonlyArray<FourSlashInterface.ReferenceGroup> | undefined): void {
|
||||
public verifyReferenceGroups(starts: ArrayOrSingle<string> | ArrayOrSingle<Range>, parts: ReadonlyArray<FourSlashInterface.ReferenceGroup>): void {
|
||||
interface ReferenceGroupJson {
|
||||
definition: string | { text: string, range: ts.TextSpan };
|
||||
references: ts.ReferenceEntry[];
|
||||
@@ -1220,7 +1219,7 @@ namespace FourSlash {
|
||||
// Necessary to have this function since `findReferences` isn't implemented in `client.ts`
|
||||
public verifyGetReferencesForServerTest(expected: ReadonlyArray<ts.ReferenceEntry>): void {
|
||||
const refs = this.getReferencesAtCaret();
|
||||
assert.deepEqual(refs, expected);
|
||||
assert.deepEqual<ReadonlyArray<ts.ReferenceEntry> | undefined>(refs, expected);
|
||||
}
|
||||
|
||||
public verifySingleReferenceGroup(definition: FourSlashInterface.ReferenceGroupDefinition, ranges?: Range[]) {
|
||||
@@ -1274,7 +1273,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
}
|
||||
|
||||
public verifyDisplayPartsOfReferencedSymbol(expected: ts.SymbolDisplayPart[]) {
|
||||
const referencedSymbols = this.findReferencesAtCaret();
|
||||
const referencedSymbols = this.findReferencesAtCaret()!;
|
||||
|
||||
if (referencedSymbols.length === 0) {
|
||||
this.raiseError("No referenced symbols found at current caret position");
|
||||
@@ -1287,11 +1286,11 @@ Actual: ${stringify(fullActual)}`);
|
||||
TestState.getDisplayPartsJson(expected), this.messageAtLastKnownMarker("referenced symbol definition display parts"));
|
||||
}
|
||||
|
||||
private getCompletionListAtCaret(options?: ts.GetCompletionsAtPositionOptions): ts.CompletionInfo {
|
||||
private getCompletionListAtCaret(options?: ts.GetCompletionsAtPositionOptions): ts.CompletionInfo | undefined {
|
||||
return this.languageService.getCompletionsAtPosition(this.activeFile.fileName, this.currentCaretPosition, options);
|
||||
}
|
||||
|
||||
private getCompletionEntryDetails(entryName: string, source?: string, preferences?: ts.UserPreferences): ts.CompletionEntryDetails {
|
||||
private getCompletionEntryDetails(entryName: string, source?: string, preferences?: ts.UserPreferences): ts.CompletionEntryDetails | undefined {
|
||||
return this.languageService.getCompletionEntryDetails(this.activeFile.fileName, this.currentCaretPosition, entryName, this.formatCodeSettings, source, preferences);
|
||||
}
|
||||
|
||||
@@ -1366,14 +1365,14 @@ Actual: ${stringify(fullActual)}`);
|
||||
tags: ts.JSDocTagInfo[]
|
||||
) {
|
||||
|
||||
const actualQuickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition);
|
||||
const actualQuickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition)!;
|
||||
assert.equal(actualQuickInfo.kind, kind, this.messageAtLastKnownMarker("QuickInfo kind"));
|
||||
assert.equal(actualQuickInfo.kindModifiers, kindModifiers, this.messageAtLastKnownMarker("QuickInfo kindModifiers"));
|
||||
assert.equal(JSON.stringify(actualQuickInfo.textSpan), JSON.stringify(textSpan), this.messageAtLastKnownMarker("QuickInfo textSpan"));
|
||||
assert.equal(TestState.getDisplayPartsJson(actualQuickInfo.displayParts), TestState.getDisplayPartsJson(displayParts), this.messageAtLastKnownMarker("QuickInfo displayParts"));
|
||||
assert.equal(TestState.getDisplayPartsJson(actualQuickInfo.documentation), TestState.getDisplayPartsJson(documentation), this.messageAtLastKnownMarker("QuickInfo documentation"));
|
||||
assert.equal(actualQuickInfo.tags.length, tags.length, this.messageAtLastKnownMarker("QuickInfo tags"));
|
||||
ts.zipWith(tags, actualQuickInfo.tags, (expectedTag, actualTag) => {
|
||||
assert.equal(actualQuickInfo.tags!.length, tags.length, this.messageAtLastKnownMarker("QuickInfo tags"));
|
||||
ts.zipWith(tags, actualQuickInfo.tags!, (expectedTag, actualTag) => {
|
||||
assert.equal(expectedTag.name, actualTag.name);
|
||||
assert.equal(expectedTag.text, actualTag.text, this.messageAtLastKnownMarker("QuickInfo tag " + actualTag.name));
|
||||
});
|
||||
@@ -1481,10 +1480,10 @@ Actual: ${stringify(fullActual)}`);
|
||||
}
|
||||
|
||||
private verifySignatureHelpWorker(options: FourSlashInterface.VerifySignatureHelpOptions) {
|
||||
const help = this.getSignatureHelp();
|
||||
const help = this.getSignatureHelp()!;
|
||||
const selectedItem = help.items[help.selectedItemIndex];
|
||||
// Argument index may exceed number of parameters
|
||||
const currentParameter: ts.SignatureHelpParameter | undefined = selectedItem.parameters[help.argumentIndex];
|
||||
const currentParameter = selectedItem.parameters[help.argumentIndex] as ts.SignatureHelpParameter | undefined;
|
||||
|
||||
assert.equal(help.items.length, options.overloadsCount || 1, this.assertionMessageAtLastKnownMarker("signature help overloads count"));
|
||||
|
||||
@@ -1539,7 +1538,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
}
|
||||
}
|
||||
|
||||
private validate(name: string, expected: string, actual: string) {
|
||||
private validate(name: string, expected: string | undefined, actual: string | undefined) {
|
||||
if (expected && expected !== actual) {
|
||||
this.raiseError("Expected " + name + " '" + expected + "'. Got '" + actual + "' instead.");
|
||||
}
|
||||
@@ -1601,19 +1600,19 @@ Actual: ${stringify(fullActual)}`);
|
||||
let nextLine = 0;
|
||||
let resultString = "";
|
||||
let currentLine: string;
|
||||
let previousSpanInfo: string;
|
||||
let startColumn: number;
|
||||
let length: number;
|
||||
let previousSpanInfo: string | undefined;
|
||||
let startColumn: number | undefined;
|
||||
let length: number | undefined;
|
||||
const prefixString = " >";
|
||||
|
||||
let pos = 0;
|
||||
const addSpanInfoString = () => {
|
||||
if (previousSpanInfo) {
|
||||
resultString += currentLine;
|
||||
let thisLineMarker = ts.repeatString(" ", startColumn) + ts.repeatString("~", length);
|
||||
let thisLineMarker = ts.repeatString(" ", startColumn!) + ts.repeatString("~", length!);
|
||||
thisLineMarker += ts.repeatString(" ", this.alignmentForExtraInfo - thisLineMarker.length - prefixString.length + 1);
|
||||
resultString += thisLineMarker;
|
||||
resultString += "=> Pos: (" + (pos - length) + " to " + (pos - 1) + ") ";
|
||||
resultString += "=> Pos: (" + (pos - length!) + " to " + (pos - 1) + ") ";
|
||||
resultString += " " + previousSpanInfo;
|
||||
previousSpanInfo = undefined;
|
||||
}
|
||||
@@ -1634,12 +1633,12 @@ Actual: ${stringify(fullActual)}`);
|
||||
if (previousSpanInfo && previousSpanInfo !== spanInfo) {
|
||||
addSpanInfoString();
|
||||
previousSpanInfo = spanInfo;
|
||||
startColumn = startColumn + length;
|
||||
startColumn = startColumn! + length!;
|
||||
length = 1;
|
||||
}
|
||||
else {
|
||||
previousSpanInfo = spanInfo;
|
||||
length++;
|
||||
length!++;
|
||||
}
|
||||
}
|
||||
addSpanInfoString();
|
||||
@@ -1660,7 +1659,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
Harness.Baseline.runBaseline(
|
||||
baselineFile,
|
||||
() => {
|
||||
return this.baselineCurrentFileLocations(pos => this.getBreakpointStatementLocation(pos));
|
||||
return this.baselineCurrentFileLocations(pos => this.getBreakpointStatementLocation(pos)!);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1693,10 +1692,10 @@ Actual: ${stringify(fullActual)}`);
|
||||
|
||||
if (emitOutput.emitSkipped) {
|
||||
resultString += "Diagnostics:" + Harness.IO.newLine();
|
||||
const diagnostics = ts.getPreEmitDiagnostics(this.languageService.getProgram());
|
||||
const diagnostics = ts.getPreEmitDiagnostics(this.languageService.getProgram()!); // TODO: GH#18217
|
||||
for (const diagnostic of diagnostics) {
|
||||
if (!ts.isString(diagnostic.messageText)) {
|
||||
let chainedMessage = diagnostic.messageText;
|
||||
let chainedMessage: ts.DiagnosticMessageChain | undefined = diagnostic.messageText;
|
||||
let indentation = " ";
|
||||
while (chainedMessage) {
|
||||
resultString += indentation + chainedMessage.messageText + Harness.IO.newLine();
|
||||
@@ -1741,7 +1740,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
}
|
||||
|
||||
public printBreakpointLocation(pos: number) {
|
||||
Harness.IO.log("\n**Pos: " + pos + " " + this.spanInfoToString(this.getBreakpointStatementLocation(pos), " "));
|
||||
Harness.IO.log("\n**Pos: " + pos + " " + this.spanInfoToString(this.getBreakpointStatementLocation(pos)!, " "));
|
||||
}
|
||||
|
||||
public printBreakpointAtCurrentLocation() {
|
||||
@@ -1754,8 +1753,8 @@ Actual: ${stringify(fullActual)}`);
|
||||
}
|
||||
|
||||
public printCurrentQuickInfo() {
|
||||
const quickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition);
|
||||
Harness.IO.log("Quick Info: " + quickInfo.displayParts.map(part => part.text).join(""));
|
||||
const quickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition)!;
|
||||
Harness.IO.log("Quick Info: " + quickInfo.displayParts!.map(part => part.text).join(""));
|
||||
}
|
||||
|
||||
public printErrorList() {
|
||||
@@ -1790,7 +1789,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
}
|
||||
|
||||
public printCurrentSignatureHelp() {
|
||||
const help = this.getSignatureHelp();
|
||||
const help = this.getSignatureHelp()!;
|
||||
Harness.IO.log(stringify(help.items[help.selectedItemIndex]));
|
||||
}
|
||||
|
||||
@@ -1803,7 +1802,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
this.printMembersOrCompletions(completions);
|
||||
}
|
||||
|
||||
private printMembersOrCompletions(info: ts.CompletionInfo) {
|
||||
private printMembersOrCompletions(info: ts.CompletionInfo | undefined) {
|
||||
if (info === undefined) { return "No completion info."; }
|
||||
const { entries } = info;
|
||||
|
||||
@@ -2087,7 +2086,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
}
|
||||
|
||||
public goToTypeDefinition(definitionIndex: number) {
|
||||
const definitions = this.languageService.getTypeDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition);
|
||||
const definitions = this.languageService.getTypeDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition)!;
|
||||
if (!definitions || !definitions.length) {
|
||||
this.raiseError("goToTypeDefinition failed - expected to find at least one definition location but got 0");
|
||||
}
|
||||
@@ -2130,7 +2129,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
}
|
||||
|
||||
public goToImplementation() {
|
||||
const implementations = this.languageService.getImplementationAtPosition(this.activeFile.fileName, this.currentCaretPosition);
|
||||
const implementations = this.languageService.getImplementationAtPosition(this.activeFile.fileName, this.currentCaretPosition)!;
|
||||
if (!implementations || !implementations.length) {
|
||||
this.raiseError("goToImplementation failed - expected to find at least one implementation location but got 0");
|
||||
}
|
||||
@@ -2145,7 +2144,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
|
||||
public verifyRangesInImplementationList(markerName: string) {
|
||||
this.goToMarker(markerName);
|
||||
const implementations: ImplementationLocationInformation[] = this.languageService.getImplementationAtPosition(this.activeFile.fileName, this.currentCaretPosition);
|
||||
const implementations: ImplementationLocationInformation[] = this.languageService.getImplementationAtPosition(this.activeFile.fileName, this.currentCaretPosition)!;
|
||||
if (!implementations || !implementations.length) {
|
||||
this.raiseError("verifyRangesInImplementationList failed - expected to find at least one implementation location but got 0");
|
||||
}
|
||||
@@ -2321,7 +2320,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
public verifyCurrentNameOrDottedNameSpanText(text: string) {
|
||||
const span = this.languageService.getNameOrDottedNameSpan(this.activeFile.fileName, this.currentCaretPosition, this.currentCaretPosition);
|
||||
if (!span) {
|
||||
this.raiseError("verifyCurrentNameOrDottedNameSpanText\n" +
|
||||
return this.raiseError("verifyCurrentNameOrDottedNameSpanText\n" +
|
||||
"\tExpected: \"" + text + "\"\n" +
|
||||
"\t Actual: undefined");
|
||||
}
|
||||
@@ -2343,12 +2342,12 @@ Actual: ${stringify(fullActual)}`);
|
||||
this.testData.globalOptions[MetadataOptionNames.baselineFile],
|
||||
() => {
|
||||
return this.baselineCurrentFileLocations(pos =>
|
||||
this.getNameOrDottedNameSpan(pos));
|
||||
this.getNameOrDottedNameSpan(pos)!);
|
||||
});
|
||||
}
|
||||
|
||||
public printNameOrDottedNameSpans(pos: number) {
|
||||
Harness.IO.log(this.spanInfoToString(this.getNameOrDottedNameSpan(pos), "**"));
|
||||
Harness.IO.log(this.spanInfoToString(this.getNameOrDottedNameSpan(pos)!, "**"));
|
||||
}
|
||||
|
||||
private verifyClassifications(expected: { classificationType: string; text: string; textSpan?: TextSpan }[], actual: ts.ClassifiedSpan[], sourceFileText: string) {
|
||||
@@ -2407,7 +2406,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
);
|
||||
assert.equal(
|
||||
expected.join(","),
|
||||
actual.fileNames.map(file => {
|
||||
actual.fileNames!.map(file => {
|
||||
return file.replace(this.basePath + "/", "");
|
||||
}).join(",")
|
||||
);
|
||||
@@ -2482,18 +2481,19 @@ Actual: ${stringify(fullActual)}`);
|
||||
public applyCodeActionFromCompletion(markerName: string, options: FourSlashInterface.VerifyCompletionActionOptions) {
|
||||
this.goToMarker(markerName);
|
||||
|
||||
const details = this.getCompletionEntryDetails(options.name, options.source, options.preferences);
|
||||
if (details.codeActions.length !== 1) {
|
||||
this.raiseError(`Expected one code action, got ${details.codeActions.length}`);
|
||||
const details = this.getCompletionEntryDetails(options.name, options.source, options.preferences)!;
|
||||
const codeActions = details.codeActions!;
|
||||
if (codeActions.length !== 1) {
|
||||
this.raiseError(`Expected one code action, got ${codeActions.length}`);
|
||||
}
|
||||
|
||||
if (details.codeActions[0].description !== options.description) {
|
||||
this.raiseError(`Expected description to be:\n${options.description}\ngot:\n${details.codeActions[0].description}`);
|
||||
if (codeActions[0].description !== options.description) {
|
||||
this.raiseError(`Expected description to be:\n${options.description}\ngot:\n${codeActions[0].description}`);
|
||||
}
|
||||
|
||||
this.applyCodeActions(details.codeActions);
|
||||
this.applyCodeActions(codeActions);
|
||||
|
||||
this.verifyNewContent(options, ts.flatMap(details.codeActions, a => a.changes.map(c => c.fileName)));
|
||||
this.verifyNewContent(options, ts.flatMap(codeActions, a => a.changes.map(c => c.fileName)));
|
||||
}
|
||||
|
||||
public verifyRangeIs(expectedText: string, includeWhiteSpace?: boolean) {
|
||||
@@ -2527,10 +2527,10 @@ Actual: ${stringify(fullActual)}`);
|
||||
const fixWithId = ts.find(this.getCodeFixes(this.activeFile.fileName), a => a.fixId === fixId);
|
||||
ts.Debug.assert(fixWithId !== undefined, "No available code fix has that group id.", () =>
|
||||
`Expected '${fixId}'. Available action ids: ${ts.mapDefined(this.getCodeFixes(this.activeFile.fileName), a => a.fixId)}`);
|
||||
ts.Debug.assertEqual(fixWithId.fixAllDescription, fixAllDescription);
|
||||
ts.Debug.assertEqual(fixWithId!.fixAllDescription, fixAllDescription);
|
||||
|
||||
const { changes, commands } = this.languageService.getCombinedCodeFix({ type: "file", fileName: this.activeFile.fileName }, fixId, this.formatCodeSettings, ts.defaultPreferences);
|
||||
assert.deepEqual(commands, expectedCommands);
|
||||
assert.deepEqual<ReadonlyArray<{}> | undefined>(commands, expectedCommands);
|
||||
assert(changes.every(c => c.fileName === this.activeFile.fileName), "TODO: support testing codefixes that touch multiple files");
|
||||
this.applyChanges(changes);
|
||||
this.verifyCurrentFileContent(newFileContent);
|
||||
@@ -2601,7 +2601,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.verifyRangeIs(options.newRangeContent, /*includeWhitespace*/ true);
|
||||
this.verifyRangeIs(options.newRangeContent!, /*includeWhitespace*/ true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2621,7 +2621,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
return;
|
||||
}
|
||||
|
||||
return this.languageService.getCodeFixesAtPosition(fileName, diagnostic.start, diagnostic.start + diagnostic.length, [diagnostic.code], this.formatCodeSettings, preferences);
|
||||
return this.languageService.getCodeFixesAtPosition(fileName, diagnostic.start!, diagnostic.start! + diagnostic.length!, [diagnostic.code], this.formatCodeSettings, preferences);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2665,7 +2665,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
}
|
||||
|
||||
const actualTextArray: string[] = [];
|
||||
const scriptInfo = this.languageServiceAdapterHost.getScriptInfo(fileName);
|
||||
const scriptInfo = this.languageServiceAdapterHost.getScriptInfo(fileName)!;
|
||||
const originalContent = scriptInfo.content;
|
||||
for (const codeFix of codeFixes) {
|
||||
ts.Debug.assert(codeFix.changes.length === 1);
|
||||
@@ -2688,7 +2688,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
|
||||
public verifyDocCommentTemplate(expected: ts.TextInsertion | undefined) {
|
||||
const name = "verifyDocCommentTemplate";
|
||||
const actual = this.languageService.getDocCommentTemplateAtPosition(this.activeFile.fileName, this.currentCaretPosition);
|
||||
const actual = this.languageService.getDocCommentTemplateAtPosition(this.activeFile.fileName, this.currentCaretPosition)!;
|
||||
|
||||
if (expected === undefined) {
|
||||
if (actual) {
|
||||
@@ -2727,7 +2727,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
const charCode = openBraceMap.get(openingBrace);
|
||||
|
||||
if (!charCode) {
|
||||
this.raiseError(`Invalid openingBrace '${openingBrace}' specified.`);
|
||||
throw this.raiseError(`Invalid openingBrace '${openingBrace}' specified.`);
|
||||
}
|
||||
|
||||
const position = this.currentCaretPosition;
|
||||
@@ -2899,7 +2899,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
const occurrences = this.getOccurrencesAtCurrentPosition();
|
||||
|
||||
if (!occurrences || occurrences.length === 0) {
|
||||
this.raiseError("verifyOccurrencesAtPositionListContains failed - found 0 references, expected at least one.");
|
||||
return this.raiseError("verifyOccurrencesAtPositionListContains failed - found 0 references, expected at least one.");
|
||||
}
|
||||
|
||||
for (const occurrence of occurrences) {
|
||||
@@ -3091,13 +3091,13 @@ Actual: ${stringify(fullActual)}`);
|
||||
|
||||
const action = ts.firstDefined(refactorsWithName, refactor => refactor.actions.find(a => a.name === actionName));
|
||||
if (!action) {
|
||||
this.raiseError(`The expected action: ${actionName} is not included in: ${ts.flatMap(refactorsWithName, r => r.actions.map(a => a.name))}`);
|
||||
throw this.raiseError(`The expected action: ${actionName} is not included in: ${ts.flatMap(refactorsWithName, r => r.actions.map(a => a.name))}`);
|
||||
}
|
||||
if (action.description !== actionDescription) {
|
||||
this.raiseError(`Expected action description to be ${JSON.stringify(actionDescription)}, got: ${JSON.stringify(action.description)}`);
|
||||
}
|
||||
|
||||
const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, this.formatCodeSettings, range, refactorName, actionName, ts.defaultPreferences);
|
||||
const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, this.formatCodeSettings, range, refactorName, actionName, ts.defaultPreferences)!;
|
||||
for (const edit of editInfo.edits) {
|
||||
this.applyEdits(edit.fileName, edit.textChanges, /*isFormattingEdit*/ false);
|
||||
}
|
||||
@@ -3144,12 +3144,12 @@ Actual: ${stringify(fullActual)}`);
|
||||
public moveToNewFile(options: FourSlashInterface.MoveToNewFileOptions): void {
|
||||
assert(this.getRanges().length === 1);
|
||||
const range = this.getRanges()[0];
|
||||
const refactor = ts.find(this.getApplicableRefactors(range, { allowTextChangesInNewFiles: true }), r => r.name === "Move to a new file");
|
||||
const refactor = ts.find(this.getApplicableRefactors(range, { allowTextChangesInNewFiles: true }), r => r.name === "Move to a new file")!;
|
||||
assert(refactor.actions.length === 1);
|
||||
const action = ts.first(refactor.actions);
|
||||
assert(action.name === "Move to a new file" && action.description === "Move to a new file");
|
||||
|
||||
const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, this.formatCodeSettings, range, refactor.name, action.name, ts.defaultPreferences);
|
||||
const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, this.formatCodeSettings, range, refactor.name, action.name, ts.defaultPreferences)!;
|
||||
for (const edit of editInfo.edits) {
|
||||
const newContent = options.newFileContents[edit.fileName];
|
||||
if (newContent === undefined) {
|
||||
@@ -3190,7 +3190,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
this.raiseError(`The expected refactor: ${refactorNameToApply} is not available at the marker location.`);
|
||||
}
|
||||
|
||||
const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, formattingOptions, markerPos, refactorNameToApply, actionName, ts.defaultPreferences);
|
||||
const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, formattingOptions, markerPos, refactorNameToApply, actionName, ts.defaultPreferences)!;
|
||||
|
||||
for (const edit of editInfo.edits) {
|
||||
this.applyEdits(edit.fileName, edit.textChanges, /*isFormattingEdit*/ false);
|
||||
@@ -3260,7 +3260,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
const item = matchingItems[0];
|
||||
|
||||
if (documentation !== undefined || text !== undefined || entryId.source !== undefined) {
|
||||
const details = this.getCompletionEntryDetails(item.name, item.source);
|
||||
const details = this.getCompletionEntryDetails(item.name, item.source)!;
|
||||
|
||||
if (documentation !== undefined) {
|
||||
eq(ts.displayPartsToString(details.documentation), documentation, "completion item documentation");
|
||||
@@ -3348,11 +3348,11 @@ Actual: ${stringify(fullActual)}`);
|
||||
|
||||
private getTextSpanForRangeAtIndex(index: number): ts.TextSpan {
|
||||
const ranges = this.getRanges();
|
||||
if (ranges && ranges.length > index) {
|
||||
if (ranges.length > index) {
|
||||
return ts.createTextSpanFromRange(ranges[index]);
|
||||
}
|
||||
else {
|
||||
this.raiseError("Supplied span index: " + index + " does not exist in range list of size: " + (ranges ? 0 : ranges.length));
|
||||
throw this.raiseError("Supplied span index: " + index + " does not exist in range list of size: " + ranges.length);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3374,8 +3374,8 @@ Actual: ${stringify(fullActual)}`);
|
||||
this.cancellationToken.resetCancelled();
|
||||
}
|
||||
|
||||
private static textSpansEqual(a: ts.TextSpan, b: ts.TextSpan) {
|
||||
return a && b && a.start === b.start && a.length === b.length;
|
||||
private static textSpansEqual(a: ts.TextSpan | undefined, b: ts.TextSpan | undefined): boolean {
|
||||
return !!a && !!b && a.start === b.start && a.length === b.length;
|
||||
}
|
||||
|
||||
public getEditsForFileRename(options: FourSlashInterface.GetEditsForFileRenameOptions): void {
|
||||
@@ -3393,7 +3393,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
}
|
||||
|
||||
export function runFourSlashTest(basePath: string, testType: FourSlashTestType, fileName: string) {
|
||||
const content = Harness.IO.readFile(fileName);
|
||||
const content = Harness.IO.readFile(fileName)!;
|
||||
runFourSlashTestContent(basePath, testType, content, fileName);
|
||||
}
|
||||
|
||||
@@ -3406,8 +3406,8 @@ Actual: ${stringify(fullActual)}`);
|
||||
const testData = parseTestData(absoluteBasePath, content, absoluteFileName);
|
||||
const state = new TestState(absoluteBasePath, testType, testData);
|
||||
const output = ts.transpileModule(content, { reportDiagnostics: true });
|
||||
if (output.diagnostics.length > 0) {
|
||||
throw new Error(`Syntax error in ${absoluteBasePath}: ${output.diagnostics[0].messageText}`);
|
||||
if (output.diagnostics!.length > 0) {
|
||||
throw new Error(`Syntax error in ${absoluteBasePath}: ${output.diagnostics![0].messageText}`);
|
||||
}
|
||||
runCode(output.outputText, state);
|
||||
}
|
||||
@@ -3558,11 +3558,11 @@ ${code}
|
||||
return Harness.getConfigNameFromFileName(file.fileName) !== undefined;
|
||||
}
|
||||
|
||||
function getNonFileNameOptionInFileList(files: FourSlashFile[]): string {
|
||||
function getNonFileNameOptionInFileList(files: FourSlashFile[]): string | undefined {
|
||||
return ts.forEach(files, f => getNonFileNameOptionInObject(f.fileOptions));
|
||||
}
|
||||
|
||||
function getNonFileNameOptionInObject(optionObject: { [s: string]: string }): string {
|
||||
function getNonFileNameOptionInObject(optionObject: { [s: string]: string }): string | undefined {
|
||||
for (const option in optionObject) {
|
||||
if (option !== MetadataOptionNames.fileName) {
|
||||
return option;
|
||||
@@ -3582,7 +3582,7 @@ ${code}
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
function recordObjectMarker(fileName: string, location: LocationInformation, text: string, markerMap: ts.Map<Marker>, markers: Marker[]): Marker {
|
||||
function recordObjectMarker(fileName: string, location: LocationInformation, text: string, markerMap: ts.Map<Marker>, markers: Marker[]): Marker | undefined {
|
||||
let markerValue: any;
|
||||
try {
|
||||
// Attempt to parse the marker value as JSON
|
||||
@@ -3613,7 +3613,7 @@ ${code}
|
||||
return marker;
|
||||
}
|
||||
|
||||
function recordMarker(fileName: string, location: LocationInformation, name: string, markerMap: ts.Map<Marker>, markers: Marker[]): Marker {
|
||||
function recordMarker(fileName: string, location: LocationInformation, name: string, markerMap: ts.Map<Marker>, markers: Marker[]): Marker | undefined {
|
||||
const marker: Marker = {
|
||||
fileName,
|
||||
position: location.position
|
||||
@@ -3642,7 +3642,7 @@ ${code}
|
||||
let output = "";
|
||||
|
||||
/// The current marker (or maybe multi-line comment?) we're parsing, possibly
|
||||
let openMarker: LocationInformation;
|
||||
let openMarker: LocationInformation | undefined;
|
||||
|
||||
/// A stack of the open range markers that are still unclosed
|
||||
const openRanges: RangeLocationInformation[] = [];
|
||||
@@ -3663,7 +3663,7 @@ ${code}
|
||||
let line = 1;
|
||||
let column = 1;
|
||||
|
||||
const flush = (lastSafeCharIndex: number) => {
|
||||
const flush = (lastSafeCharIndex: number | undefined) => {
|
||||
output = output + content.substr(lastNormalCharPosition, lastSafeCharIndex === undefined ? undefined : lastSafeCharIndex - lastNormalCharPosition);
|
||||
};
|
||||
|
||||
@@ -3690,7 +3690,7 @@ ${code}
|
||||
// found a range end
|
||||
const rangeStart = openRanges.pop();
|
||||
if (!rangeStart) {
|
||||
reportError(fileName, line, column, "Found range end with no matching start.");
|
||||
throw reportError(fileName, line, column, "Found range end with no matching start.");
|
||||
}
|
||||
|
||||
const range: Range = {
|
||||
@@ -3733,8 +3733,8 @@ ${code}
|
||||
// Object markers are only ever terminated by |} and have no content restrictions
|
||||
if (previousChar === "|" && currentChar === "}") {
|
||||
// Record the marker
|
||||
const objectMarkerNameText = content.substring(openMarker.sourcePosition + 2, i - 1).trim();
|
||||
const marker = recordObjectMarker(fileName, openMarker, objectMarkerNameText, markerMap, markers);
|
||||
const objectMarkerNameText = content.substring(openMarker!.sourcePosition + 2, i - 1).trim();
|
||||
const marker = recordObjectMarker(fileName, openMarker!, objectMarkerNameText, markerMap, markers);
|
||||
|
||||
if (openRanges.length > 0) {
|
||||
openRanges[openRanges.length - 1].marker = marker;
|
||||
@@ -3742,7 +3742,7 @@ ${code}
|
||||
|
||||
// Set the current start to point to the end of the current marker to ignore its text
|
||||
lastNormalCharPosition = i + 1;
|
||||
difference += i + 1 - openMarker.sourcePosition;
|
||||
difference += i + 1 - openMarker!.sourcePosition;
|
||||
|
||||
// Reset the state
|
||||
openMarker = undefined;
|
||||
@@ -3754,17 +3754,17 @@ ${code}
|
||||
if (previousChar === "*" && currentChar === "/") {
|
||||
// Record the marker
|
||||
// start + 2 to ignore the */, -1 on the end to ignore the * (/ is next)
|
||||
const markerNameText = content.substring(openMarker.sourcePosition + 2, i - 1).trim();
|
||||
const marker = recordMarker(fileName, openMarker, markerNameText, markerMap, markers);
|
||||
const markerNameText = content.substring(openMarker!.sourcePosition + 2, i - 1).trim();
|
||||
const marker = recordMarker(fileName, openMarker!, markerNameText, markerMap, markers);
|
||||
|
||||
if (openRanges.length > 0) {
|
||||
openRanges[openRanges.length - 1].marker = marker;
|
||||
}
|
||||
|
||||
// Set the current start to point to the end of the current marker to ignore its text
|
||||
flush(openMarker.sourcePosition);
|
||||
flush(openMarker!.sourcePosition);
|
||||
lastNormalCharPosition = i + 1;
|
||||
difference += i + 1 - openMarker.sourcePosition;
|
||||
difference += i + 1 - openMarker!.sourcePosition;
|
||||
|
||||
// Reset the state
|
||||
openMarker = undefined;
|
||||
@@ -3865,7 +3865,7 @@ ${code}
|
||||
return s.replace(/\s/g, "");
|
||||
}
|
||||
|
||||
function findDuplicatedElement<T>(a: ReadonlyArray<T>, equal: (a: T, b: T) => boolean): T {
|
||||
function findDuplicatedElement<T>(a: ReadonlyArray<T>, equal: (a: T, b: T) => boolean): T | undefined {
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
for (let j = i + 1; j < a.length; j++) {
|
||||
if (equal(a[i], a[j])) {
|
||||
@@ -3889,7 +3889,7 @@ namespace FourSlashInterface {
|
||||
return this.state.getMarkerNames();
|
||||
}
|
||||
|
||||
public marker(name?: string): FourSlash.Marker {
|
||||
public marker(name: string): FourSlash.Marker {
|
||||
return this.state.getMarkerByName(name);
|
||||
}
|
||||
|
||||
@@ -3936,7 +3936,7 @@ namespace FourSlashInterface {
|
||||
public eachMarker(action: (marker: FourSlash.Marker, index: number) => void): void;
|
||||
public eachMarker(a: ReadonlyArray<string> | ((marker: FourSlash.Marker, index: number) => void), b?: (marker: FourSlash.Marker, index: number) => void): void {
|
||||
const markers = typeof a === "function" ? this.state.getMarkers() : a.map(m => this.state.getMarkerByName(m));
|
||||
this.state.goToEachMarker(markers, typeof a === "function" ? a : b);
|
||||
this.state.goToEachMarker(markers, typeof a === "function" ? a : b!);
|
||||
}
|
||||
|
||||
|
||||
@@ -4146,7 +4146,7 @@ namespace FourSlashInterface {
|
||||
this.state.verifyQuickInfoString(expectedText, expectedDocumentation);
|
||||
}
|
||||
|
||||
public quickInfoAt(markerName: string, expectedText?: string, expectedDocumentation?: string) {
|
||||
public quickInfoAt(markerName: string, expectedText: string, expectedDocumentation?: string) {
|
||||
this.state.verifyQuickInfoAt(markerName, expectedText, expectedDocumentation);
|
||||
}
|
||||
|
||||
@@ -4765,7 +4765,7 @@ namespace FourSlashInterface {
|
||||
readonly exact?: ArrayOrSingle<ExpectedCompletionEntry>;
|
||||
readonly includes?: ArrayOrSingle<ExpectedCompletionEntry>;
|
||||
readonly excludes?: ArrayOrSingle<string | { readonly name: string, readonly source: string }>;
|
||||
readonly preferences: ts.UserPreferences;
|
||||
readonly preferences?: ts.UserPreferences;
|
||||
readonly triggerCharacter?: ts.CompletionsTriggerCharacter;
|
||||
}
|
||||
|
||||
|
||||
+53
-54
@@ -148,7 +148,7 @@ namespace Utils {
|
||||
path = "tests/" + path;
|
||||
}
|
||||
|
||||
let content: string;
|
||||
let content: string | undefined;
|
||||
try {
|
||||
content = Harness.IO.readFile(Harness.userSpecifiedRoot + path);
|
||||
}
|
||||
@@ -177,7 +177,7 @@ namespace Utils {
|
||||
|
||||
export const canonicalizeForHarness = ts.createGetCanonicalFileName(/*caseSensitive*/ false); // This is done so tests work on windows _and_ linux
|
||||
|
||||
export function assertInvariants(node: ts.Node, parent: ts.Node): void {
|
||||
export function assertInvariants(node: ts.Node | undefined, parent: ts.Node | undefined): void {
|
||||
if (node) {
|
||||
assert.isFalse(node.pos < 0, "node.pos < 0");
|
||||
assert.isFalse(node.end < 0, "node.end < 0");
|
||||
@@ -504,11 +504,11 @@ namespace Harness {
|
||||
newLine(): string;
|
||||
getCurrentDirectory(): string;
|
||||
useCaseSensitiveFileNames(): boolean;
|
||||
resolvePath(path: string): string;
|
||||
resolvePath(path: string): string | undefined;
|
||||
getFileSize(path: string): number;
|
||||
readFile(path: string): string | undefined;
|
||||
writeFile(path: string, contents: string): void;
|
||||
directoryName(path: string): string;
|
||||
directoryName(path: string): string | undefined;
|
||||
getDirectories(path: string): string[];
|
||||
createDirectory(path: string): void;
|
||||
fileExists(fileName: string): boolean;
|
||||
@@ -525,7 +525,7 @@ namespace Harness {
|
||||
getAccessibleFileSystemEntries(dirname: string): ts.FileSystemEntries;
|
||||
tryEnableSourceMapsForHost?(): void;
|
||||
getEnvironmentVariable?(name: string): string;
|
||||
getMemoryUsage?(): number;
|
||||
getMemoryUsage?(): number | undefined;
|
||||
}
|
||||
|
||||
export let IO: IO;
|
||||
@@ -564,9 +564,7 @@ namespace Harness {
|
||||
return runner.enumerateTestFiles();
|
||||
}
|
||||
|
||||
function listFiles(path: string, spec: RegExp, options?: { recursive?: boolean }) {
|
||||
options = options || {};
|
||||
|
||||
function listFiles(path: string, spec: RegExp, options: { recursive?: boolean } = {}) {
|
||||
function filesInFolder(folder: string): string[] {
|
||||
let paths: string[] = [];
|
||||
|
||||
@@ -634,7 +632,7 @@ namespace Harness {
|
||||
getCurrentDirectory: () => ts.sys.getCurrentDirectory(),
|
||||
useCaseSensitiveFileNames: () => ts.sys.useCaseSensitiveFileNames,
|
||||
resolvePath: (path: string) => ts.sys.resolvePath(path),
|
||||
getFileSize: (path: string) => ts.sys.getFileSize(path),
|
||||
getFileSize: (path: string) => ts.sys.getFileSize!(path),
|
||||
readFile: path => ts.sys.readFile(path),
|
||||
writeFile: (path, content) => ts.sys.writeFile(path, content),
|
||||
directoryName,
|
||||
@@ -692,7 +690,7 @@ namespace Harness {
|
||||
}
|
||||
}
|
||||
|
||||
public static combine(left: HttpHeaders | undefined, right: HttpHeaders | undefined): HttpHeaders {
|
||||
public static combine(left: HttpHeaders | undefined, right: HttpHeaders | undefined): HttpHeaders | undefined {
|
||||
if (!left && !right) return undefined;
|
||||
const headers = new HttpHeaders();
|
||||
if (left) left.forEach((value, key) => { headers.set(key, value); });
|
||||
@@ -768,8 +766,8 @@ namespace Harness {
|
||||
public static readResponseContent(xhr: XMLHttpRequest) {
|
||||
if (typeof xhr.responseText === "string") {
|
||||
return new HttpContent({
|
||||
"Content-Type": xhr.getResponseHeader("Content-Type") || undefined,
|
||||
"Content-Length": xhr.getResponseHeader("Content-Length") || undefined
|
||||
"Content-Type": xhr.getResponseHeader("Content-Type") || undefined!, // TODO: GH#18217
|
||||
"Content-Length": xhr.getResponseHeader("Content-Length") || undefined!, // TODO: GH#18217
|
||||
}, xhr.responseText);
|
||||
}
|
||||
return undefined;
|
||||
@@ -888,7 +886,7 @@ namespace Harness {
|
||||
|
||||
function getFileSize(path: string): number {
|
||||
const response = send(HttpRequestMessage.head(new URL(path, serverRoot)));
|
||||
return HttpResponseMessage.hasSuccessStatusCode(response) ? +response.headers.get("Content-Length").toString() : 0;
|
||||
return HttpResponseMessage.hasSuccessStatusCode(response) ? +response.headers.get("Content-Length")!.toString() : 0;
|
||||
}
|
||||
|
||||
function readFile(path: string): string | undefined {
|
||||
@@ -998,7 +996,7 @@ namespace Harness {
|
||||
}
|
||||
}
|
||||
|
||||
if (Harness.IO.tryEnableSourceMapsForHost && /^development$/i.test(Harness.IO.getEnvironmentVariable("NODE_ENV"))) {
|
||||
if (Harness.IO.tryEnableSourceMapsForHost && /^development$/i.test(Harness.IO.getEnvironmentVariable!("NODE_ENV"))) {
|
||||
Harness.IO.tryEnableSourceMapsForHost();
|
||||
}
|
||||
|
||||
@@ -1030,7 +1028,7 @@ namespace Harness {
|
||||
*/
|
||||
export class WriterAggregator {
|
||||
public lines: string[] = [];
|
||||
public currentLine = <string>undefined;
|
||||
public currentLine: string = undefined!;
|
||||
|
||||
public Write(str: string) {
|
||||
// out of memory usage concerns avoid using + or += if we're going to do any manipulation of this string later
|
||||
@@ -1040,17 +1038,17 @@ namespace Harness {
|
||||
public WriteLine(str: string) {
|
||||
// out of memory usage concerns avoid using + or += if we're going to do any manipulation of this string later
|
||||
this.lines.push([(this.currentLine || ""), str].join(""));
|
||||
this.currentLine = undefined;
|
||||
this.currentLine = undefined!;
|
||||
}
|
||||
|
||||
public Close() {
|
||||
if (this.currentLine !== undefined) { this.lines.push(this.currentLine); }
|
||||
this.currentLine = undefined;
|
||||
this.currentLine = undefined!;
|
||||
}
|
||||
|
||||
public reset() {
|
||||
this.lines = [];
|
||||
this.currentLine = undefined;
|
||||
this.currentLine = undefined!;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1077,20 +1075,20 @@ namespace Harness {
|
||||
// Cache of lib files from "built/local"
|
||||
let libFileNameSourceFileMap: ts.Map<ts.SourceFile> | undefined;
|
||||
|
||||
export function getDefaultLibrarySourceFile(fileName = defaultLibFileName): ts.SourceFile {
|
||||
export function getDefaultLibrarySourceFile(fileName = defaultLibFileName): ts.SourceFile | undefined {
|
||||
if (!isDefaultLibraryFile(fileName)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!libFileNameSourceFileMap) {
|
||||
libFileNameSourceFileMap = ts.createMapFromTemplate({
|
||||
[defaultLibFileName]: createSourceFileAndAssertInvariants(defaultLibFileName, IO.readFile(libFolder + "lib.es5.d.ts"), /*languageVersion*/ ts.ScriptTarget.Latest)
|
||||
[defaultLibFileName]: createSourceFileAndAssertInvariants(defaultLibFileName, IO.readFile(libFolder + "lib.es5.d.ts")!, /*languageVersion*/ ts.ScriptTarget.Latest)
|
||||
});
|
||||
}
|
||||
|
||||
let sourceFile = libFileNameSourceFileMap.get(fileName);
|
||||
if (!sourceFile) {
|
||||
libFileNameSourceFileMap.set(fileName, sourceFile = createSourceFileAndAssertInvariants(fileName, IO.readFile(libFolder + fileName), ts.ScriptTarget.Latest));
|
||||
libFileNameSourceFileMap.set(fileName, sourceFile = createSourceFileAndAssertInvariants(fileName, IO.readFile(libFolder + fileName)!, ts.ScriptTarget.Latest));
|
||||
}
|
||||
return sourceFile;
|
||||
}
|
||||
@@ -1206,10 +1204,10 @@ namespace Harness {
|
||||
export function compileFiles(
|
||||
inputFiles: TestFile[],
|
||||
otherFiles: TestFile[],
|
||||
harnessSettings: TestCaseParser.CompilerSettings,
|
||||
compilerOptions: ts.CompilerOptions,
|
||||
harnessSettings: TestCaseParser.CompilerSettings | undefined,
|
||||
compilerOptions: ts.CompilerOptions | undefined,
|
||||
// Current directory is needed for rwcRunner to be able to use currentDirectory defined in json file
|
||||
currentDirectory: string): compiler.CompilationResult {
|
||||
currentDirectory: string | undefined): compiler.CompilationResult {
|
||||
const options: ts.CompilerOptions & HarnessOptions = compilerOptions ? ts.cloneCompilerOptions(compilerOptions) : { noResolve: false };
|
||||
options.target = options.target || ts.ScriptTarget.ES3;
|
||||
options.newLine = options.newLine || ts.NewLineKind.CarriageReturnLineFeed;
|
||||
@@ -1225,7 +1223,7 @@ namespace Harness {
|
||||
setCompilerOptionsFromHarnessSetting(harnessSettings, options);
|
||||
}
|
||||
if (options.rootDirs) {
|
||||
options.rootDirs = ts.map(options.rootDirs, d => ts.getNormalizedAbsolutePath(d, currentDirectory));
|
||||
options.rootDirs = ts.map(options.rootDirs, d => ts.getNormalizedAbsolutePath(d, currentDirectory!));
|
||||
}
|
||||
|
||||
const useCaseSensitiveFileNames = options.useCaseSensitiveFileNames !== undefined ? options.useCaseSensitiveFileNames : true;
|
||||
@@ -1253,7 +1251,7 @@ namespace Harness {
|
||||
export interface DeclarationCompilationContext {
|
||||
declInputFiles: TestFile[];
|
||||
declOtherFiles: TestFile[];
|
||||
harnessSettings: TestCaseParser.CompilerSettings & HarnessOptions;
|
||||
harnessSettings: TestCaseParser.CompilerSettings & HarnessOptions | undefined;
|
||||
options: ts.CompilerOptions;
|
||||
currentDirectory: string;
|
||||
}
|
||||
@@ -1264,7 +1262,7 @@ namespace Harness {
|
||||
harnessSettings: TestCaseParser.CompilerSettings & HarnessOptions,
|
||||
options: ts.CompilerOptions,
|
||||
// Current directory is needed for rwcRunner to be able to use currentDirectory defined in json file
|
||||
currentDirectory: string): DeclarationCompilationContext | undefined {
|
||||
currentDirectory: string | undefined): DeclarationCompilationContext | undefined {
|
||||
|
||||
if (options.declaration && result.diagnostics.length === 0) {
|
||||
if (options.emitDeclarationOnly) {
|
||||
@@ -1300,7 +1298,7 @@ namespace Harness {
|
||||
}
|
||||
|
||||
function findResultCodeFile(fileName: string) {
|
||||
const sourceFile = result.program.getSourceFile(fileName);
|
||||
const sourceFile = result.program!.getSourceFile(fileName)!;
|
||||
assert(sourceFile, "Program has no source file with name '" + fileName + "'");
|
||||
// Is this file going to be emitted separately
|
||||
let sourceFileName: string;
|
||||
@@ -1308,7 +1306,7 @@ namespace Harness {
|
||||
if (!outFile) {
|
||||
if (options.outDir) {
|
||||
let sourceFilePath = ts.getNormalizedAbsolutePath(sourceFile.fileName, result.vfs.cwd());
|
||||
sourceFilePath = sourceFilePath.replace(result.program.getCommonSourceDirectory(), "");
|
||||
sourceFilePath = sourceFilePath.replace(result.program!.getCommonSourceDirectory(), "");
|
||||
sourceFileName = ts.combinePaths(options.outDir, sourceFilePath);
|
||||
}
|
||||
else {
|
||||
@@ -1408,7 +1406,7 @@ namespace Harness {
|
||||
// Filter down to the errors in the file
|
||||
const fileErrors = diagnostics.filter((e): e is ts.DiagnosticWithLocation => {
|
||||
const errFn = e.file;
|
||||
return errFn && utils.removeTestPathPrefixes(errFn.fileName) === utils.removeTestPathPrefixes(inputFile.unitName);
|
||||
return !!errFn && utils.removeTestPathPrefixes(errFn.fileName) === utils.removeTestPathPrefixes(inputFile.unitName);
|
||||
});
|
||||
|
||||
|
||||
@@ -1443,7 +1441,8 @@ namespace Harness {
|
||||
}
|
||||
// Emit this line from the original file
|
||||
outputLines += (newLine() + " " + line);
|
||||
fileErrors.forEach(err => {
|
||||
fileErrors.forEach(errDiagnostic => {
|
||||
const err = errDiagnostic as ts.TextSpan; // TODO: GH#18217
|
||||
// Does any error start or continue on to this line? Emit squiggles
|
||||
const end = ts.textSpanEnd(err);
|
||||
if ((end >= thisLineStart) && ((err.start < nextLineStart) || (lineIndex === lines.length - 1))) {
|
||||
@@ -1461,7 +1460,7 @@ namespace Harness {
|
||||
// Just like above, we need to do a split on a string instead of on a regex
|
||||
// because the JS engine does regexes wrong
|
||||
|
||||
outputErrorText(err);
|
||||
outputErrorText(errDiagnostic);
|
||||
markedErrorCount++;
|
||||
}
|
||||
}
|
||||
@@ -1476,12 +1475,12 @@ namespace Harness {
|
||||
}
|
||||
|
||||
const numLibraryDiagnostics = ts.countWhere(diagnostics, diagnostic => {
|
||||
return diagnostic.file && (isDefaultLibraryFile(diagnostic.file.fileName) || isBuiltFile(diagnostic.file.fileName));
|
||||
return !!diagnostic.file && (isDefaultLibraryFile(diagnostic.file.fileName) || isBuiltFile(diagnostic.file.fileName));
|
||||
});
|
||||
|
||||
const numTest262HarnessDiagnostics = ts.countWhere(diagnostics, diagnostic => {
|
||||
// Count an error generated from tests262-harness folder.This should only apply for test262
|
||||
return diagnostic.file && diagnostic.file.fileName.indexOf("test262-harness") >= 0;
|
||||
return !!diagnostic.file && diagnostic.file.fileName.indexOf("test262-harness") >= 0;
|
||||
});
|
||||
|
||||
// Verify we didn't miss any errors in total
|
||||
@@ -1489,7 +1488,7 @@ namespace Harness {
|
||||
}
|
||||
|
||||
export function doErrorBaseline(baselinePath: string, inputFiles: ReadonlyArray<TestFile>, errors: ReadonlyArray<ts.Diagnostic>, pretty?: boolean) {
|
||||
Baseline.runBaseline(baselinePath.replace(/\.tsx?$/, ".errors.txt"), (): string => {
|
||||
Baseline.runBaseline(baselinePath.replace(/\.tsx?$/, ".errors.txt"), (): string | null => {
|
||||
if (!errors || (errors.length === 0)) {
|
||||
/* tslint:disable:no-null-keyword */
|
||||
return null;
|
||||
@@ -1519,7 +1518,7 @@ namespace Harness {
|
||||
|
||||
// Produce baselines. The first gives the types for all expressions.
|
||||
// The second gives symbols for all identifiers.
|
||||
let typesError: Error, symbolsError: Error;
|
||||
let typesError: Error | undefined, symbolsError: Error | undefined;
|
||||
try {
|
||||
checkBaseLines(/*isSymbolBaseLine*/ false);
|
||||
}
|
||||
@@ -1567,7 +1566,7 @@ namespace Harness {
|
||||
}
|
||||
}
|
||||
|
||||
function generateBaseLine(isSymbolBaseline: boolean, skipBaseline?: boolean): string {
|
||||
function generateBaseLine(isSymbolBaseline: boolean, skipBaseline?: boolean): string | null {
|
||||
let result = "";
|
||||
const gen = iterateBaseLine(isSymbolBaseline, skipBaseline);
|
||||
for (let {done, value} = gen.next(); !done; { done, value } = gen.next()) {
|
||||
@@ -1754,7 +1753,7 @@ namespace Harness {
|
||||
resultName = sanitizeTestFilePath(resultName);
|
||||
if (dupeCase.has(resultName)) {
|
||||
// A different baseline filename should be manufactured if the names differ only in case, for windows compat
|
||||
const count = 1 + dupeCase.get(resultName);
|
||||
const count = 1 + dupeCase.get(resultName)!;
|
||||
dupeCase.set(resultName, count);
|
||||
resultName = `${resultName}.dupe${count}`;
|
||||
}
|
||||
@@ -1862,7 +1861,7 @@ namespace Harness {
|
||||
export function extractCompilerSettings(content: string): CompilerSettings {
|
||||
const opts: CompilerSettings = {};
|
||||
|
||||
let match: RegExpExecArray;
|
||||
let match: RegExpExecArray | null;
|
||||
/* tslint:disable:no-null-keyword */
|
||||
while ((match = optionRegex.exec(content)) !== null) {
|
||||
/* tslint:enable:no-null-keyword */
|
||||
@@ -1875,8 +1874,8 @@ namespace Harness {
|
||||
export interface TestCaseContent {
|
||||
settings: CompilerSettings;
|
||||
testUnitData: TestUnitData[];
|
||||
tsConfig: ts.ParsedCommandLine;
|
||||
tsConfigFileUnitData: TestUnitData;
|
||||
tsConfig: ts.ParsedCommandLine | undefined;
|
||||
tsConfigFileUnitData: TestUnitData | undefined;
|
||||
}
|
||||
|
||||
/** Given a test file containing // @FileName directives, return an array of named units of code to be added to an existing compiler instance */
|
||||
@@ -1887,7 +1886,7 @@ namespace Harness {
|
||||
const lines = Utils.splitContentByNewlines(code);
|
||||
|
||||
// Stuff related to the subfile we're parsing
|
||||
let currentFileContent: string;
|
||||
let currentFileContent: string | undefined;
|
||||
let currentFileOptions: any = {};
|
||||
let currentFileName: any;
|
||||
let refs: string[] = [];
|
||||
@@ -1907,7 +1906,7 @@ namespace Harness {
|
||||
if (currentFileName) {
|
||||
// Store result file
|
||||
const newTestFile = {
|
||||
content: currentFileContent,
|
||||
content: currentFileContent!, // TODO: GH#18217
|
||||
name: currentFileName,
|
||||
fileOptions: currentFileOptions,
|
||||
originalFilePath: fileName,
|
||||
@@ -1962,8 +1961,8 @@ namespace Harness {
|
||||
};
|
||||
|
||||
// check if project has tsconfig.json in the list of files
|
||||
let tsConfig: ts.ParsedCommandLine;
|
||||
let tsConfigFileUnitData: TestUnitData;
|
||||
let tsConfig: ts.ParsedCommandLine | undefined;
|
||||
let tsConfigFileUnitData: TestUnitData | undefined;
|
||||
for (let i = 0; i < testUnitData.length; i++) {
|
||||
const data = testUnitData[i];
|
||||
if (getConfigNameFromFileName(data.name)) {
|
||||
@@ -2024,7 +2023,7 @@ namespace Harness {
|
||||
}
|
||||
|
||||
const fileCache: { [idx: string]: boolean } = {};
|
||||
function generateActual(generateContent: () => string): string {
|
||||
function generateActual(generateContent: () => string | null): string | null {
|
||||
|
||||
const actual = generateContent();
|
||||
|
||||
@@ -2035,12 +2034,12 @@ namespace Harness {
|
||||
return actual;
|
||||
}
|
||||
|
||||
function compareToBaseline(actual: string, relativeFileName: string, opts: BaselineOptions) {
|
||||
function compareToBaseline(actual: string | null, relativeFileName: string, opts: BaselineOptions | undefined) {
|
||||
// actual is now either undefined (the generator had an error), null (no file requested),
|
||||
// or some real output of the function
|
||||
if (actual === undefined) {
|
||||
// Nothing to do
|
||||
return;
|
||||
return undefined!; // TODO: GH#18217
|
||||
}
|
||||
|
||||
const refFileName = referencePath(relativeFileName, opts && opts.Baselinefolder, opts && opts.Subfolder);
|
||||
@@ -2053,7 +2052,7 @@ namespace Harness {
|
||||
|
||||
let expected = "<no content>";
|
||||
if (IO.fileExists(refFileName)) {
|
||||
expected = IO.readFile(refFileName);
|
||||
expected = IO.readFile(refFileName)!; // TODO: GH#18217
|
||||
}
|
||||
|
||||
return { expected, actual };
|
||||
@@ -2069,7 +2068,7 @@ namespace Harness {
|
||||
return;
|
||||
}
|
||||
|
||||
const parentDirectory = IO.directoryName(dirName);
|
||||
const parentDirectory = IO.directoryName(dirName)!; // TODO: GH#18217
|
||||
if (parentDirectory !== "" && parentDirectory !== dirName) {
|
||||
createDirectoryStructure(parentDirectory);
|
||||
}
|
||||
@@ -2078,7 +2077,7 @@ namespace Harness {
|
||||
}
|
||||
|
||||
// Create folders if needed
|
||||
createDirectoryStructure(IO.directoryName(actualFileName));
|
||||
createDirectoryStructure(IO.directoryName(actualFileName)!); // TODO: GH#18217
|
||||
|
||||
// Delete the actual file in case it fails
|
||||
if (IO.fileExists(actualFileName)) {
|
||||
@@ -2097,14 +2096,14 @@ namespace Harness {
|
||||
}
|
||||
}
|
||||
|
||||
export function runBaseline(relativeFileName: string, generateContent: () => string, opts?: BaselineOptions): void {
|
||||
export function runBaseline(relativeFileName: string, generateContent: () => string | null, opts?: BaselineOptions): void {
|
||||
const actualFileName = localPath(relativeFileName, opts && opts.Baselinefolder, opts && opts.Subfolder);
|
||||
const actual = generateActual(generateContent);
|
||||
const comparison = compareToBaseline(actual, relativeFileName, opts);
|
||||
writeComparison(comparison.expected, comparison.actual, relativeFileName, actualFileName);
|
||||
}
|
||||
|
||||
export function runMultifileBaseline(relativeFileBase: string, extension: string, generateContent: () => IterableIterator<[string, string, number]> | IterableIterator<[string, string]>, opts?: BaselineOptions, referencedExtensions?: string[]): void {
|
||||
export function runMultifileBaseline(relativeFileBase: string, extension: string, generateContent: () => IterableIterator<[string, string, number]> | IterableIterator<[string, string]> | null, opts?: BaselineOptions, referencedExtensions?: string[]): void {
|
||||
const gen = generateContent();
|
||||
const writtenFiles = ts.createMap<true>();
|
||||
const errors: Error[] = [];
|
||||
@@ -2175,7 +2174,7 @@ namespace Harness {
|
||||
|
||||
export function getDefaultLibraryFile(filePath: string, io: IO): Compiler.TestFile {
|
||||
const libFile = userSpecifiedRoot + libFolder + ts.getBaseFileName(ts.normalizeSlashes(filePath));
|
||||
return { unitName: libFile, content: io.readFile(libFile) };
|
||||
return { unitName: libFile, content: io.readFile(libFile)! };
|
||||
}
|
||||
|
||||
export function getConfigNameFromFileName(filename: string): "tsconfig.json" | "jsconfig.json" | undefined {
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Harness.LanguageService {
|
||||
export class ScriptInfo {
|
||||
public version = 1;
|
||||
public editRanges: { length: number; textChangeRange: ts.TextChangeRange; }[] = [];
|
||||
private lineMap: number[] = undefined;
|
||||
private lineMap: number[] | undefined;
|
||||
|
||||
constructor(public fileName: string, public content: string, public isRootFile: boolean) {
|
||||
this.setContent(content);
|
||||
@@ -95,7 +95,7 @@ namespace Harness.LanguageService {
|
||||
return this.scriptSnapshot.getLength();
|
||||
}
|
||||
|
||||
public getChangeRange(oldScript: ts.ScriptSnapshotShim): string {
|
||||
public getChangeRange(oldScript: ts.ScriptSnapshotShim): string | undefined {
|
||||
const range = this.scriptSnapshot.getChangeRange((oldScript as ScriptSnapshotProxy).scriptSnapshot);
|
||||
return range && JSON.stringify(range);
|
||||
}
|
||||
@@ -146,7 +146,7 @@ namespace Harness.LanguageService {
|
||||
return fileNames;
|
||||
}
|
||||
|
||||
public getScriptInfo(fileName: string): ScriptInfo {
|
||||
public getScriptInfo(fileName: string): ScriptInfo | undefined {
|
||||
return this.scriptInfos.get(vpath.resolve(this.vfs.cwd(), fileName));
|
||||
}
|
||||
|
||||
@@ -175,9 +175,8 @@ namespace Harness.LanguageService {
|
||||
* @param col 0 based index
|
||||
*/
|
||||
public positionToLineAndCharacter(fileName: string, position: number): ts.LineAndCharacter {
|
||||
const script: ScriptInfo = this.getScriptInfo(fileName);
|
||||
const script: ScriptInfo = this.getScriptInfo(fileName)!;
|
||||
assert.isOk(script);
|
||||
|
||||
return ts.computeLineAndCharacterOfPosition(script.getLineMap(), position);
|
||||
}
|
||||
}
|
||||
@@ -185,7 +184,7 @@ namespace Harness.LanguageService {
|
||||
/// Native adapter
|
||||
class NativeLanguageServiceHost extends LanguageServiceAdapterHost implements ts.LanguageServiceHost, LanguageServiceAdapterHost {
|
||||
isKnownTypesPackageName(name: string): boolean {
|
||||
return this.typesRegistry && this.typesRegistry.has(name);
|
||||
return !!this.typesRegistry && this.typesRegistry.has(name);
|
||||
}
|
||||
|
||||
installPackage = ts.notImplemented;
|
||||
@@ -206,7 +205,7 @@ namespace Harness.LanguageService {
|
||||
return this.getFilenames().filter(ts.isAnySupportedFileExtension);
|
||||
}
|
||||
|
||||
getScriptSnapshot(fileName: string): ts.IScriptSnapshot {
|
||||
getScriptSnapshot(fileName: string): ts.IScriptSnapshot | undefined {
|
||||
const script = this.getScriptInfo(fileName);
|
||||
return script ? new ScriptSnapshot(script) : undefined;
|
||||
}
|
||||
@@ -215,7 +214,7 @@ namespace Harness.LanguageService {
|
||||
|
||||
getScriptVersion(fileName: string): string {
|
||||
const script = this.getScriptInfo(fileName);
|
||||
return script ? script.version.toString() : undefined;
|
||||
return script ? script.version.toString() : undefined!; // TODO: GH#18217
|
||||
}
|
||||
|
||||
directoryExists(dirName: string): boolean {
|
||||
@@ -280,7 +279,7 @@ namespace Harness.LanguageService {
|
||||
}
|
||||
};
|
||||
this.getModuleResolutionsForFile = (fileName) => {
|
||||
const scriptInfo = this.getScriptInfo(fileName);
|
||||
const scriptInfo = this.getScriptInfo(fileName)!;
|
||||
const preprocessInfo = ts.preProcessFile(scriptInfo.content, /*readImportFiles*/ true);
|
||||
const imports: ts.MapLike<string> = {};
|
||||
for (const module of preprocessInfo.importedFiles) {
|
||||
@@ -299,8 +298,8 @@ namespace Harness.LanguageService {
|
||||
const settings = this.nativeHost.getCompilationSettings();
|
||||
for (const typeReferenceDirective of preprocessInfo.typeReferenceDirectives) {
|
||||
const resolutionInfo = ts.resolveTypeReferenceDirective(typeReferenceDirective.fileName, fileName, settings, moduleResolutionHost);
|
||||
if (resolutionInfo.resolvedTypeReferenceDirective.resolvedFileName) {
|
||||
resolutions[typeReferenceDirective.fileName] = resolutionInfo.resolvedTypeReferenceDirective;
|
||||
if (resolutionInfo.resolvedTypeReferenceDirective!.resolvedFileName) {
|
||||
resolutions[typeReferenceDirective.fileName] = resolutionInfo.resolvedTypeReferenceDirective!;
|
||||
}
|
||||
}
|
||||
return JSON.stringify(resolutions);
|
||||
@@ -313,7 +312,7 @@ namespace Harness.LanguageService {
|
||||
}
|
||||
|
||||
getFilenames(): string[] { return this.nativeHost.getFilenames(); }
|
||||
getScriptInfo(fileName: string): ScriptInfo { return this.nativeHost.getScriptInfo(fileName); }
|
||||
getScriptInfo(fileName: string): ScriptInfo | undefined { return this.nativeHost.getScriptInfo(fileName); }
|
||||
addScript(fileName: string, content: string, isRootFile: boolean): void { this.nativeHost.addScript(fileName, content, isRootFile); }
|
||||
editScript(fileName: string, start: number, end: number, newText: string): void { this.nativeHost.editScript(fileName, start, end, newText); }
|
||||
positionToLineAndCharacter(fileName: string, position: number): ts.LineAndCharacter { return this.nativeHost.positionToLineAndCharacter(fileName, position); }
|
||||
@@ -325,7 +324,7 @@ namespace Harness.LanguageService {
|
||||
getDefaultLibFileName(): string { return this.nativeHost.getDefaultLibFileName(); }
|
||||
getScriptFileNames(): string { return JSON.stringify(this.nativeHost.getScriptFileNames()); }
|
||||
getScriptSnapshot(fileName: string): ts.ScriptSnapshotShim {
|
||||
const nativeScriptSnapshot = this.nativeHost.getScriptSnapshot(fileName);
|
||||
const nativeScriptSnapshot = this.nativeHost.getScriptSnapshot(fileName)!; // TODO: GH#18217
|
||||
return nativeScriptSnapshot && new ScriptSnapshotProxy(nativeScriptSnapshot);
|
||||
}
|
||||
getScriptKind(): ts.ScriptKind { return this.nativeHost.getScriptKind(); }
|
||||
@@ -504,7 +503,7 @@ namespace Harness.LanguageService {
|
||||
getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: ts.FormatCodeOptions): ts.TextChange[] {
|
||||
return unwrapJSONCallResult(this.shim.getFormattingEditsAfterKeystroke(fileName, position, key, JSON.stringify(options)));
|
||||
}
|
||||
getDocCommentTemplateAtPosition(fileName: string, position: number): ts.TextInsertion | undefined {
|
||||
getDocCommentTemplateAtPosition(fileName: string, position: number): ts.TextInsertion {
|
||||
return unwrapJSONCallResult(this.shim.getDocCommentTemplateAtPosition(fileName, position));
|
||||
}
|
||||
isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean {
|
||||
@@ -608,7 +607,7 @@ namespace Harness.LanguageService {
|
||||
class SessionClientHost extends NativeLanguageServiceHost implements ts.server.SessionClientHost {
|
||||
private client: ts.server.SessionClient;
|
||||
|
||||
constructor(cancellationToken: ts.HostCancellationToken, settings: ts.CompilerOptions) {
|
||||
constructor(cancellationToken: ts.HostCancellationToken | undefined, settings: ts.CompilerOptions | undefined) {
|
||||
super(cancellationToken, settings);
|
||||
}
|
||||
|
||||
@@ -715,7 +714,7 @@ namespace Harness.LanguageService {
|
||||
return true;
|
||||
}
|
||||
|
||||
getLogFileName(): string {
|
||||
getLogFileName(): string | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -850,7 +849,7 @@ namespace Harness.LanguageService {
|
||||
cancellationToken: ts.server.nullCancellationToken,
|
||||
useSingleInferredProject: false,
|
||||
useInferredProjectPerProjectRoot: false,
|
||||
typingsInstaller: undefined,
|
||||
typingsInstaller: undefined!, // TODO: GH#18217
|
||||
byteLength: Utils.byteLength,
|
||||
hrtime: process.hrtime,
|
||||
logger: serverHost,
|
||||
|
||||
+38
-35
@@ -68,10 +68,10 @@ interface IoLog {
|
||||
}[];
|
||||
directoriesRead: {
|
||||
path: string,
|
||||
extensions: ReadonlyArray<string>,
|
||||
exclude: ReadonlyArray<string>,
|
||||
include: ReadonlyArray<string>,
|
||||
depth: number,
|
||||
extensions: ReadonlyArray<string> | undefined,
|
||||
exclude: ReadonlyArray<string> | undefined,
|
||||
include: ReadonlyArray<string> | undefined,
|
||||
depth: number | undefined,
|
||||
result: ReadonlyArray<string>,
|
||||
}[];
|
||||
useCaseSensitiveFileNames?: boolean;
|
||||
@@ -87,8 +87,8 @@ interface PlaybackControl {
|
||||
}
|
||||
|
||||
namespace Playback {
|
||||
let recordLog: IoLog;
|
||||
let replayLog: IoLog;
|
||||
let recordLog: IoLog | undefined;
|
||||
let replayLog: IoLog | undefined;
|
||||
let replayFilesRead: ts.Map<IoLogFile> | undefined;
|
||||
let recordLogFileNameBase = "";
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace Playback {
|
||||
return lookup[s] = func(s);
|
||||
});
|
||||
run.reset = () => {
|
||||
lookup = undefined;
|
||||
lookup = undefined!; // TODO: GH#18217
|
||||
};
|
||||
|
||||
return run;
|
||||
@@ -148,11 +148,12 @@ namespace Playback {
|
||||
}
|
||||
}
|
||||
for (const file of log.filesRead) {
|
||||
if (file.result.contentsPath) {
|
||||
const result = file.result!; // TODO: GH#18217
|
||||
if (result.contentsPath) {
|
||||
// `readFile` strips away a BOM (and actually reinerprets the file contents according to the correct encoding)
|
||||
// - but this has the unfortunate sideeffect of removing the BOM from any outputs based on the file, so we readd it here.
|
||||
file.result.contents = (file.result.bom || "") + host.readFile(ts.combinePaths(baseName, file.result.contentsPath));
|
||||
delete file.result.contentsPath;
|
||||
result.contents = (result.bom || "") + host.readFile(ts.combinePaths(baseName, result.contentsPath));
|
||||
delete result.contentsPath;
|
||||
}
|
||||
}
|
||||
return log;
|
||||
@@ -188,21 +189,22 @@ namespace Playback {
|
||||
}
|
||||
if (log.filesRead) {
|
||||
for (const file of log.filesRead) {
|
||||
const { contents } = file.result;
|
||||
const result = file.result!; // TODO: GH#18217
|
||||
const { contents } = result;
|
||||
if (contents !== undefined) {
|
||||
file.result.contentsPath = ts.combinePaths("read", sanitizeTestFilePath(file.path));
|
||||
writeFile(ts.combinePaths(baseTestName, file.result.contentsPath), contents);
|
||||
result.contentsPath = ts.combinePaths("read", sanitizeTestFilePath(file.path));
|
||||
writeFile(ts.combinePaths(baseTestName, result.contentsPath), contents);
|
||||
const len = contents.length;
|
||||
if (len >= 2 && contents.charCodeAt(0) === 0xfeff) {
|
||||
file.result.bom = "\ufeff";
|
||||
result.bom = "\ufeff";
|
||||
}
|
||||
if (len >= 2 && contents.charCodeAt(0) === 0xfffe) {
|
||||
file.result.bom = "\ufffe";
|
||||
result.bom = "\ufffe";
|
||||
}
|
||||
if (len >= 3 && contents.charCodeAt(0) === 0xefbb && contents.charCodeAt(1) === 0xbf) {
|
||||
file.result.bom = "\uefbb\xbf";
|
||||
result.bom = "\uefbb\xbf";
|
||||
}
|
||||
delete file.result.contents;
|
||||
delete result.contents;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -222,7 +224,7 @@ namespace Playback {
|
||||
wrapper.startReplayFromData = log => {
|
||||
replayLog = log;
|
||||
// Remove non-found files from the log (shouldn't really need them, but we still record them for diagnostic purposes)
|
||||
replayLog.filesRead = replayLog.filesRead.filter(f => f.result.contents !== undefined);
|
||||
replayLog.filesRead = replayLog.filesRead.filter(f => f.result!.contents !== undefined);
|
||||
replayFilesRead = ts.createMap();
|
||||
for (const file of replayLog.filesRead) {
|
||||
replayFilesRead.set(ts.normalizeSlashes(file.path).toLowerCase(), file);
|
||||
@@ -244,7 +246,7 @@ namespace Playback {
|
||||
};
|
||||
|
||||
wrapper.startReplayFromFile = logFn => {
|
||||
wrapper.startReplayFromString(underlying.readFile(logFn));
|
||||
wrapper.startReplayFromString(underlying.readFile(logFn)!);
|
||||
};
|
||||
wrapper.endRecord = () => {
|
||||
if (recordLog !== undefined) {
|
||||
@@ -267,24 +269,25 @@ namespace Playback {
|
||||
}
|
||||
const files = [];
|
||||
for (const file of newLog.filesRead) {
|
||||
if (file.result.contentsPath &&
|
||||
Harness.isDefaultLibraryFile(file.result.contentsPath) &&
|
||||
/\.[tj]s$/.test(file.result.contentsPath)) {
|
||||
files.push(file.result.contentsPath);
|
||||
const result = file.result!;
|
||||
if (result.contentsPath &&
|
||||
Harness.isDefaultLibraryFile(result.contentsPath) &&
|
||||
/\.[tj]s$/.test(result.contentsPath)) {
|
||||
files.push(result.contentsPath);
|
||||
}
|
||||
}
|
||||
return { compilerOptions: ts.parseCommandLine(newLog.arguments).options, files };
|
||||
}
|
||||
|
||||
wrapper.fileExists = recordReplay(wrapper.fileExists, underlying)(
|
||||
path => callAndRecord(underlying.fileExists(path), recordLog.fileExists, { path }),
|
||||
path => callAndRecord(underlying.fileExists(path), recordLog!.fileExists, { path }),
|
||||
memoize(path => {
|
||||
// If we read from the file, it must exist
|
||||
if (findFileByPath(path, /*throwFileNotFoundError*/ false)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return findResultByFields(replayLog.fileExists, { path }, /*defaultValue*/ false);
|
||||
return findResultByFields(replayLog!.fileExists, { path }, /*defaultValue*/ false)!;
|
||||
}
|
||||
})
|
||||
);
|
||||
@@ -314,22 +317,22 @@ namespace Playback {
|
||||
};
|
||||
|
||||
wrapper.resolvePath = recordReplay(wrapper.resolvePath, underlying)(
|
||||
path => callAndRecord(underlying.resolvePath(path), recordLog.pathsResolved, { path }),
|
||||
memoize(path => findResultByFields(replayLog.pathsResolved, { path }, !ts.isRootedDiskPath(ts.normalizeSlashes(path)) && replayLog.currentDirectory ? replayLog.currentDirectory + "/" + path : ts.normalizeSlashes(path))));
|
||||
path => callAndRecord(underlying.resolvePath(path), recordLog!.pathsResolved, { path }),
|
||||
memoize(path => findResultByFields(replayLog!.pathsResolved, { path }, !ts.isRootedDiskPath(ts.normalizeSlashes(path)) && replayLog!.currentDirectory ? replayLog!.currentDirectory + "/" + path : ts.normalizeSlashes(path))));
|
||||
|
||||
wrapper.readFile = recordReplay(wrapper.readFile, underlying)(
|
||||
(path: string) => {
|
||||
const result = underlying.readFile(path);
|
||||
const logEntry = { path, codepage: 0, result: { contents: result, codepage: 0 } };
|
||||
recordLog.filesRead.push(logEntry);
|
||||
recordLog!.filesRead.push(logEntry);
|
||||
return result;
|
||||
},
|
||||
memoize(path => findFileByPath(path, /*throwFileNotFoundError*/ true).contents));
|
||||
memoize(path => findFileByPath(path, /*throwFileNotFoundError*/ true)!.contents));
|
||||
|
||||
wrapper.readDirectory = recordReplay(wrapper.readDirectory, underlying)(
|
||||
(path, extensions, exclude, include, depth) => {
|
||||
const result = (<ts.System>underlying).readDirectory(path, extensions, exclude, include, depth);
|
||||
recordLog.directoriesRead.push({ path, extensions, exclude, include, depth, result });
|
||||
recordLog!.directoriesRead.push({ path, extensions, exclude, include, depth, result });
|
||||
return result;
|
||||
},
|
||||
path => {
|
||||
@@ -338,7 +341,7 @@ namespace Playback {
|
||||
// different entry).
|
||||
// TODO (yuisu): We can certainly remove these once we recapture the RWC using new API
|
||||
const normalizedPath = ts.normalizePath(path).toLowerCase();
|
||||
return ts.flatMap(replayLog.directoriesRead, directory => {
|
||||
return ts.flatMap(replayLog!.directoriesRead, directory => {
|
||||
if (ts.normalizeSlashes(directory.path).toLowerCase() === normalizedPath) {
|
||||
return directory.result;
|
||||
}
|
||||
@@ -346,7 +349,7 @@ namespace Playback {
|
||||
});
|
||||
|
||||
wrapper.writeFile = recordReplay(wrapper.writeFile, underlying)(
|
||||
(path: string, contents: string) => callAndRecord(underlying.writeFile(path, contents), recordLog.filesWritten, { path, contents, bom: false }),
|
||||
(path: string, contents: string) => callAndRecord(underlying.writeFile(path, contents), recordLog!.filesWritten, { path, contents, bom: false }),
|
||||
() => noOpReplay("writeFile"));
|
||||
|
||||
wrapper.exit = (exitCode) => {
|
||||
@@ -390,7 +393,7 @@ namespace Playback {
|
||||
return underlyingResult;
|
||||
}
|
||||
|
||||
function findResultByFields<T>(logArray: { result?: T }[], expectedFields: {}, defaultValue?: T): T {
|
||||
function findResultByFields<T>(logArray: { result?: T }[], expectedFields: {}, defaultValue?: T): T | undefined {
|
||||
const predicate = (entry: { result?: T }) => {
|
||||
return Object.getOwnPropertyNames(expectedFields).every((name) => (<any>entry)[name] === (<any>expectedFields)[name]);
|
||||
};
|
||||
@@ -406,10 +409,10 @@ namespace Playback {
|
||||
return results[0].result;
|
||||
}
|
||||
|
||||
function findFileByPath(expectedPath: string, throwFileNotFoundError: boolean): FileInformation {
|
||||
function findFileByPath(expectedPath: string, throwFileNotFoundError: boolean): FileInformation | undefined {
|
||||
const normalizedName = ts.normalizePath(expectedPath).toLowerCase();
|
||||
// Try to find the result through normal fileName
|
||||
const result = replayFilesRead.get(normalizedName);
|
||||
const result = replayFilesRead!.get(normalizedName);
|
||||
if (result) {
|
||||
return result.result;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// tslint:disable no-unnecessary-type-assertion (TODO: tslint can't find node types)
|
||||
|
||||
if (typeof describe === "undefined") {
|
||||
(global as any).describe = undefined; // If launched without mocha for parallel mode, we still need a global describe visible to satisfy the parsing of the unit tests
|
||||
(global as any).it = undefined;
|
||||
@@ -32,7 +34,7 @@ namespace Harness.Parallel.Host {
|
||||
function perfdataFileName(target?: string) {
|
||||
return `${perfdataFileNameFragment}${target ? `.${target}` : ""}.json`;
|
||||
}
|
||||
function readSavedPerfData(target?: string): {[testHash: string]: number} {
|
||||
function readSavedPerfData(target?: string): {[testHash: string]: number} | undefined {
|
||||
const perfDataContents = IO.readFile(perfdataFileName(target));
|
||||
if (perfDataContents) {
|
||||
return JSON.parse(perfDataContents);
|
||||
@@ -73,7 +75,7 @@ namespace Harness.Parallel.Host {
|
||||
setTimeout(() => startDelayed(perfData, totalCost), 0); // Do real startup on next tick, so all unit tests have been collected
|
||||
}
|
||||
|
||||
function startDelayed(perfData: {[testHash: string]: number}, totalCost: number) {
|
||||
function startDelayed(perfData: {[testHash: string]: number} | undefined, totalCost: number) {
|
||||
initializeProgressBarsDependencies();
|
||||
console.log(`Discovered ${tasks.length} unittest suites` + (newTasks.length ? ` and ${newTasks.length} new suites.` : "."));
|
||||
console.log("Discovering runner-based tests...");
|
||||
@@ -227,16 +229,16 @@ namespace Harness.Parallel.Host {
|
||||
return;
|
||||
}
|
||||
// Send tasks in blocks if the tasks are small
|
||||
const taskList = [tasks.pop()];
|
||||
const taskList = [tasks.pop()!];
|
||||
while (tasks.length && taskList.reduce((p, c) => p + c.size, 0) < chunkSize) {
|
||||
taskList.push(tasks.pop());
|
||||
taskList.push(tasks.pop()!);
|
||||
}
|
||||
child.currentTasks = taskList;
|
||||
if (taskList.length === 1) {
|
||||
child.send({ type: "test", payload: taskList[0] });
|
||||
child.send({ type: "test", payload: taskList[0] } as ParallelHostMessage); // TODO: GH#18217
|
||||
}
|
||||
else {
|
||||
child.send({ type: "batch", payload: taskList });
|
||||
child.send({ type: "batch", payload: taskList } as ParallelHostMessage); // TODO: GH#18217
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -268,7 +270,7 @@ namespace Harness.Parallel.Host {
|
||||
doneBatching[i] = true;
|
||||
continue;
|
||||
}
|
||||
const task = tasks.pop();
|
||||
const task = tasks.pop()!;
|
||||
batches[i].push(task);
|
||||
scheduledTotal += task.size;
|
||||
}
|
||||
@@ -293,7 +295,7 @@ namespace Harness.Parallel.Host {
|
||||
worker.send({ type: "batch", payload });
|
||||
}
|
||||
else { // Out of batches, send off just one test
|
||||
const payload = tasks.pop();
|
||||
const payload = tasks.pop()!;
|
||||
ts.Debug.assert(!!payload); // The reserve kept above should ensure there is always an initial task available, even in suboptimal scenarios
|
||||
worker.currentTasks = [payload];
|
||||
worker.send({ type: "test", payload });
|
||||
@@ -302,7 +304,7 @@ namespace Harness.Parallel.Host {
|
||||
}
|
||||
else {
|
||||
for (let i = 0; i < workerCount; i++) {
|
||||
const task = tasks.pop();
|
||||
const task = tasks.pop()!;
|
||||
workers[i].currentTasks = [task];
|
||||
workers[i].send({ type: "test", payload: task });
|
||||
}
|
||||
@@ -519,7 +521,7 @@ namespace Harness.Parallel.Host {
|
||||
this._enabled = false;
|
||||
}
|
||||
}
|
||||
update(index: number, percentComplete: number, color: string, title: string, titleColor?: string) {
|
||||
update(index: number, percentComplete: number, color: string, title: string | undefined, titleColor?: string) {
|
||||
percentComplete = minMax(percentComplete, 0, 1);
|
||||
|
||||
const progressBar = this._progressBars[index] || (this._progressBars[index] = { });
|
||||
@@ -555,7 +557,7 @@ namespace Harness.Parallel.Host {
|
||||
}
|
||||
|
||||
cursor.hide();
|
||||
readline.moveCursor(process.stdout, -process.stdout.columns, -this._lineCount);
|
||||
readline.moveCursor(process.stdout, -process.stdout.columns!, -this._lineCount);
|
||||
let lineCount = 0;
|
||||
const numProgressBars = this._progressBars.length;
|
||||
for (let i = 0; i < numProgressBars; i++) {
|
||||
@@ -564,7 +566,7 @@ namespace Harness.Parallel.Host {
|
||||
process.stdout.write(this._progressBars[i].text + os.EOL);
|
||||
}
|
||||
else {
|
||||
readline.moveCursor(process.stdout, -process.stdout.columns, +1);
|
||||
readline.moveCursor(process.stdout, -process.stdout.columns!, +1);
|
||||
}
|
||||
|
||||
lineCount++;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// tslint:disable no-unnecessary-type-assertion (TODO: tslint can't find node types)
|
||||
|
||||
namespace Harness.Parallel.Worker {
|
||||
let errors: ErrorInfo[] = [];
|
||||
let passes: TestInfo[] = [];
|
||||
@@ -35,7 +37,7 @@ namespace Harness.Parallel.Worker {
|
||||
if (!testList) {
|
||||
throw new Error("Tests must occur within a describe block");
|
||||
}
|
||||
testList.push({ name, callback, kind: "test" });
|
||||
testList.push({ name, callback: callback!, kind: "test" });
|
||||
}) as Mocha.ITestDefinition;
|
||||
(global as any).it.skip = ts.noop;
|
||||
}
|
||||
@@ -43,18 +45,18 @@ namespace Harness.Parallel.Worker {
|
||||
function setTimeoutAndExecute(timeout: number | undefined, f: () => void) {
|
||||
if (timeout !== undefined) {
|
||||
const timeoutMsg: ParallelTimeoutChangeMessage = { type: "timeout", payload: { duration: timeout } };
|
||||
process.send(timeoutMsg);
|
||||
process.send!(timeoutMsg);
|
||||
}
|
||||
f();
|
||||
if (timeout !== undefined) {
|
||||
// Reset timeout
|
||||
const timeoutMsg: ParallelTimeoutChangeMessage = { type: "timeout", payload: { duration: "reset" } };
|
||||
process.send(timeoutMsg);
|
||||
process.send!(timeoutMsg);
|
||||
}
|
||||
}
|
||||
|
||||
function executeSuiteCallback(name: string, callback: MochaCallback) {
|
||||
let timeout: number;
|
||||
let timeout: number | undefined;
|
||||
const fakeContext: Mocha.ISuiteCallbackContext = {
|
||||
retries() { return this; },
|
||||
slow() { return this; },
|
||||
@@ -64,9 +66,9 @@ namespace Harness.Parallel.Worker {
|
||||
},
|
||||
};
|
||||
namestack.push(name);
|
||||
let beforeFunc: Callable;
|
||||
let beforeFunc: Callable | undefined;
|
||||
(before as any) = (cb: Callable) => beforeFunc = cb;
|
||||
let afterFunc: Callable;
|
||||
let afterFunc: Callable | undefined;
|
||||
(after as any) = (cb: Callable) => afterFunc = cb;
|
||||
const savedBeforeEach = beforeEachFunc;
|
||||
(beforeEach as any) = (cb: Callable) => beforeEachFunc = cb;
|
||||
@@ -127,13 +129,13 @@ namespace Harness.Parallel.Worker {
|
||||
}
|
||||
|
||||
function executeTestCallback(name: string, callback: MochaCallback) {
|
||||
let timeout: number;
|
||||
let timeout: number | undefined;
|
||||
const fakeContext: Mocha.ITestCallbackContext = {
|
||||
skip() { return this; },
|
||||
timeout(n: number) {
|
||||
timeout = n;
|
||||
const timeoutMsg: ParallelTimeoutChangeMessage = { type: "timeout", payload: { duration: timeout } };
|
||||
process.send(timeoutMsg);
|
||||
process.send!(timeoutMsg);
|
||||
return this;
|
||||
},
|
||||
retries() { return this; },
|
||||
@@ -164,7 +166,7 @@ namespace Harness.Parallel.Worker {
|
||||
namestack.pop();
|
||||
if (timeout !== undefined) {
|
||||
const timeoutMsg: ParallelTimeoutChangeMessage = { type: "timeout", payload: { duration: "reset" } };
|
||||
process.send(timeoutMsg);
|
||||
process.send!(timeoutMsg);
|
||||
}
|
||||
}
|
||||
passing++;
|
||||
@@ -195,7 +197,7 @@ namespace Harness.Parallel.Worker {
|
||||
namestack.pop();
|
||||
if (timeout !== undefined) {
|
||||
const timeoutMsg: ParallelTimeoutChangeMessage = { type: "timeout", payload: { duration: "reset" } };
|
||||
process.send(timeoutMsg);
|
||||
process.send!(timeoutMsg);
|
||||
}
|
||||
}
|
||||
if (!completed) {
|
||||
@@ -219,7 +221,7 @@ namespace Harness.Parallel.Worker {
|
||||
console.error(data);
|
||||
}
|
||||
const message: ParallelResultMessage = { type: "result", payload: handleTest(runner, file) };
|
||||
process.send(message);
|
||||
process.send!(message);
|
||||
break;
|
||||
case "close":
|
||||
process.exit(0);
|
||||
@@ -239,16 +241,16 @@ namespace Harness.Parallel.Worker {
|
||||
else {
|
||||
message = { type: "progress", payload };
|
||||
}
|
||||
process.send(message);
|
||||
process.send!(message);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
process.on("uncaughtException", error => {
|
||||
const message: ParallelErrorMessage = { type: "error", payload: { error: error.message, stack: error.stack, name: [...namestack] } };
|
||||
const message: ParallelErrorMessage = { type: "error", payload: { error: error.message, stack: error.stack!, name: [...namestack] } };
|
||||
try {
|
||||
process.send(message);
|
||||
process.send!(message);
|
||||
}
|
||||
catch (e) {
|
||||
console.error(error);
|
||||
@@ -273,7 +275,7 @@ namespace Harness.Parallel.Worker {
|
||||
if (!runners.has(runner)) {
|
||||
runners.set(runner, createRunner(runner));
|
||||
}
|
||||
const instance = runners.get(runner);
|
||||
const instance = runners.get(runner)!;
|
||||
instance.tests = [file];
|
||||
return { ...resetShimHarnessAndExecute(instance), runner, file };
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ namespace project {
|
||||
this.compilerOptions = createCompilerOptions(testCase, moduleKind);
|
||||
this.sys = new fakes.System(vfs);
|
||||
|
||||
let configFileName: string;
|
||||
let configFileName: string | undefined;
|
||||
let inputFiles = testCase.inputFiles;
|
||||
if (this.compilerOptions.project) {
|
||||
// Parse project
|
||||
@@ -145,7 +145,7 @@ namespace project {
|
||||
configFileName = ts.findConfigFile("", path => this.sys.fileExists(path));
|
||||
}
|
||||
|
||||
let errors: ts.Diagnostic[];
|
||||
let errors: ts.Diagnostic[] | undefined;
|
||||
const configFileSourceFiles: ts.SourceFile[] = [];
|
||||
if (configFileName) {
|
||||
const result = ts.readJsonConfigFile(configFileName, path => this.sys.readFile(path));
|
||||
@@ -178,7 +178,7 @@ namespace project {
|
||||
public static getConfigurations(testCaseFileName: string): ProjectTestConfiguration[] {
|
||||
let testCase: ProjectRunnerTestCase & ts.CompilerOptions;
|
||||
|
||||
let testFileText: string;
|
||||
let testFileText: string | undefined;
|
||||
try {
|
||||
testFileText = Harness.IO.readFile(testCaseFileName);
|
||||
}
|
||||
@@ -187,10 +187,10 @@ namespace project {
|
||||
}
|
||||
|
||||
try {
|
||||
testCase = <ProjectRunnerTestCase & ts.CompilerOptions>JSON.parse(testFileText);
|
||||
testCase = <ProjectRunnerTestCase & ts.CompilerOptions>JSON.parse(testFileText!);
|
||||
}
|
||||
catch (e) {
|
||||
assert(false, "Testcase: " + testCaseFileName + " does not contain valid json format: " + e.message);
|
||||
throw assert(false, "Testcase: " + testCaseFileName + " does not contain valid json format: " + e.message);
|
||||
}
|
||||
|
||||
const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false);
|
||||
@@ -209,12 +209,12 @@ namespace project {
|
||||
const cwd = this.vfs.cwd();
|
||||
const ignoreCase = this.vfs.ignoreCase;
|
||||
const resolutionInfo: ProjectRunnerTestCaseResolutionInfo & ts.CompilerOptions = JSON.parse(JSON.stringify(this.testCase));
|
||||
resolutionInfo.resolvedInputFiles = this.compilerResult.program.getSourceFiles()
|
||||
resolutionInfo.resolvedInputFiles = this.compilerResult.program!.getSourceFiles()
|
||||
.map(({ fileName: input }) => vpath.beneath(vfs.builtFolder, input, this.vfs.ignoreCase) || vpath.beneath(vfs.testLibFolder, input, this.vfs.ignoreCase) ? utils.removeTestPathPrefixes(input) :
|
||||
vpath.isAbsolute(input) ? vpath.relative(cwd, input, ignoreCase) :
|
||||
input);
|
||||
|
||||
resolutionInfo.emittedFiles = this.compilerResult.outputFiles
|
||||
resolutionInfo.emittedFiles = this.compilerResult.outputFiles!
|
||||
.map(output => output.meta.get("fileName") || output.file)
|
||||
.map(output => utils.removeTestPathPrefixes(vpath.isAbsolute(output) ? vpath.relative(cwd, output, ignoreCase) : output));
|
||||
|
||||
@@ -234,7 +234,7 @@ namespace project {
|
||||
if (this.testCase.baselineCheck) {
|
||||
const errs: Error[] = [];
|
||||
let nonSubfolderDiskFiles = 0;
|
||||
for (const output of this.compilerResult.outputFiles) {
|
||||
for (const output of this.compilerResult.outputFiles!) {
|
||||
try {
|
||||
// convert file name to rooted name
|
||||
// if filename is not rooted - concat it with project root and then expand project root relative to current directory
|
||||
@@ -252,7 +252,7 @@ namespace project {
|
||||
}
|
||||
|
||||
const content = utils.removeTestPathPrefixes(output.text, /*retainTrailingDirectorySeparator*/ true);
|
||||
Harness.Baseline.runBaseline(this.getBaselineFolder(this.compilerResult.moduleKind) + diskRelativeName, () => content);
|
||||
Harness.Baseline.runBaseline(this.getBaselineFolder(this.compilerResult.moduleKind) + diskRelativeName, () => content as string | null); // TODO: GH#18217
|
||||
}
|
||||
catch (e) {
|
||||
errs.push(e);
|
||||
@@ -292,7 +292,7 @@ namespace project {
|
||||
}
|
||||
|
||||
private cleanProjectUrl(url: string) {
|
||||
let diskProjectPath = ts.normalizeSlashes(Harness.IO.resolvePath(this.testCase.projectRoot));
|
||||
let diskProjectPath = ts.normalizeSlashes(Harness.IO.resolvePath(this.testCase.projectRoot)!);
|
||||
let projectRootUrl = "file:///" + diskProjectPath;
|
||||
const normalizedProjectRoot = ts.normalizeSlashes(this.testCase.projectRoot);
|
||||
diskProjectPath = diskProjectPath.substr(0, diskProjectPath.lastIndexOf(normalizedProjectRoot));
|
||||
@@ -362,10 +362,10 @@ namespace project {
|
||||
rootFiles.unshift(sourceFile.fileName);
|
||||
}
|
||||
else if (!(compilerOptions.outFile || compilerOptions.out)) {
|
||||
let emitOutputFilePathWithoutExtension: string;
|
||||
let emitOutputFilePathWithoutExtension: string | undefined;
|
||||
if (compilerOptions.outDir) {
|
||||
let sourceFilePath = ts.getNormalizedAbsolutePath(sourceFile.fileName, compilerResult.program.getCurrentDirectory());
|
||||
sourceFilePath = sourceFilePath.replace(compilerResult.program.getCommonSourceDirectory(), "");
|
||||
let sourceFilePath = ts.getNormalizedAbsolutePath(sourceFile.fileName, compilerResult.program!.getCurrentDirectory());
|
||||
sourceFilePath = sourceFilePath.replace(compilerResult.program!.getCommonSourceDirectory(), "");
|
||||
emitOutputFilePathWithoutExtension = ts.removeFileExtension(ts.combinePaths(compilerOptions.outDir, sourceFilePath));
|
||||
}
|
||||
else {
|
||||
@@ -380,8 +380,8 @@ namespace project {
|
||||
}
|
||||
}
|
||||
else {
|
||||
const outputDtsFileName = ts.removeFileExtension(compilerOptions.outFile || compilerOptions.out) + ts.Extension.Dts;
|
||||
const outputDtsFile = findOutputDtsFile(outputDtsFileName);
|
||||
const outputDtsFileName = ts.removeFileExtension(compilerOptions.outFile || compilerOptions.out!) + ts.Extension.Dts;
|
||||
const outputDtsFile = findOutputDtsFile(outputDtsFileName)!;
|
||||
if (!ts.contains(allInputFiles, outputDtsFile)) {
|
||||
allInputFiles.unshift(outputDtsFile);
|
||||
rootFiles.unshift(outputDtsFile.meta.get("fileName") || outputDtsFile.file);
|
||||
@@ -395,8 +395,8 @@ namespace project {
|
||||
});
|
||||
|
||||
// Dont allow config files since we are compiling existing source options
|
||||
const compilerHost = new ProjectCompilerHost(_vfs, compilerResult.compilerOptions, this.testCaseJustName, this.testCase, compilerResult.moduleKind);
|
||||
return this.compileProjectFiles(compilerResult.moduleKind, compilerResult.configFileSourceFiles, () => rootFiles, compilerHost, compilerResult.compilerOptions);
|
||||
const compilerHost = new ProjectCompilerHost(_vfs, compilerResult.compilerOptions!, this.testCaseJustName, this.testCase, compilerResult.moduleKind);
|
||||
return this.compileProjectFiles(compilerResult.moduleKind, compilerResult.configFileSourceFiles, () => rootFiles, compilerHost, compilerResult.compilerOptions!);
|
||||
|
||||
function findOutputDtsFile(fileName: string) {
|
||||
return ts.forEach(compilerResult.outputFiles, outputFile => outputFile.meta.get("fileName") === fileName ? outputFile : undefined);
|
||||
|
||||
@@ -65,7 +65,7 @@ function createRunner(kind: TestRunnerKind): RunnerBase {
|
||||
case "dt":
|
||||
return new DefinitelyTypedRunner();
|
||||
}
|
||||
ts.Debug.fail(`Unknown runner kind ${kind}`);
|
||||
return ts.Debug.fail(`Unknown runner kind ${kind}`);
|
||||
}
|
||||
|
||||
// users can define tests to run in mytest.config that will override cmd line args, otherwise use cmd line args (test.config), otherwise no options
|
||||
@@ -76,10 +76,10 @@ const testconfigFileName = "test.config";
|
||||
const customConfig = tryGetConfig(Harness.IO.args());
|
||||
let testConfigContent =
|
||||
customConfig && Harness.IO.fileExists(customConfig)
|
||||
? Harness.IO.readFile(customConfig)
|
||||
? Harness.IO.readFile(customConfig)!
|
||||
: Harness.IO.fileExists(mytestconfigFileName)
|
||||
? Harness.IO.readFile(mytestconfigFileName)
|
||||
: Harness.IO.fileExists(testconfigFileName) ? Harness.IO.readFile(testconfigFileName) : "";
|
||||
? Harness.IO.readFile(mytestconfigFileName)!
|
||||
: Harness.IO.fileExists(testconfigFileName) ? Harness.IO.readFile(testconfigFileName)! : "";
|
||||
|
||||
let taskConfigsFolder: string;
|
||||
let workerCount: number;
|
||||
@@ -131,9 +131,9 @@ function handleTestConfig() {
|
||||
(<any>Error).stackTraceLimit = Infinity;
|
||||
stackTraceLimit = testConfig.stackTraceLimit;
|
||||
}
|
||||
else if ((+testConfig.stackTraceLimit | 0) > 0) {
|
||||
(<any>Error).stackTraceLimit = +testConfig.stackTraceLimit | 0;
|
||||
stackTraceLimit = +testConfig.stackTraceLimit | 0;
|
||||
else if ((+testConfig.stackTraceLimit! | 0) > 0) {
|
||||
(<any>Error).stackTraceLimit = +testConfig.stackTraceLimit! | 0;
|
||||
stackTraceLimit = +testConfig.stackTraceLimit! | 0;
|
||||
}
|
||||
if (testConfig.listenForWork) {
|
||||
return true;
|
||||
@@ -222,6 +222,7 @@ function handleTestConfig() {
|
||||
if (runUnitTests === undefined) {
|
||||
runUnitTests = runners.length !== 1; // Don't run unit tests when running only one runner if unit tests were not explicitly asked for
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function beginTests() {
|
||||
|
||||
+15
-15
@@ -41,22 +41,22 @@ namespace RWC {
|
||||
inputFiles = [];
|
||||
otherFiles = [];
|
||||
tsconfigFiles = [];
|
||||
compilerResult = undefined;
|
||||
compilerOptions = undefined;
|
||||
currentDirectory = undefined;
|
||||
compilerResult = undefined!;
|
||||
compilerOptions = undefined!;
|
||||
currentDirectory = undefined!;
|
||||
// useCustomLibraryFile is a flag specified in the json object to indicate whether to use built/local/lib.d.ts
|
||||
// or to use lib.d.ts inside the json object. If the flag is true, use the lib.d.ts inside json file
|
||||
// otherwise use the lib.d.ts from built/local
|
||||
useCustomLibraryFile = undefined;
|
||||
useCustomLibraryFile = undefined!;
|
||||
});
|
||||
|
||||
it("can compile", function(this: Mocha.ITestCallbackContext) {
|
||||
this.timeout(800_000); // Allow long timeouts for RWC compilations
|
||||
let opts: ts.ParsedCommandLine;
|
||||
let opts!: ts.ParsedCommandLine;
|
||||
|
||||
const ioLog: IoLog = Playback.newStyleLogIntoOldStyleLog(JSON.parse(Harness.IO.readFile(`internal/cases/rwc/${jsonPath}/test.json`)), Harness.IO, `internal/cases/rwc/${baseName}`);
|
||||
const ioLog: IoLog = Playback.newStyleLogIntoOldStyleLog(JSON.parse(Harness.IO.readFile(`internal/cases/rwc/${jsonPath}/test.json`)!), Harness.IO, `internal/cases/rwc/${baseName}`);
|
||||
currentDirectory = ioLog.currentDirectory;
|
||||
useCustomLibraryFile = ioLog.useCustomLibraryFile;
|
||||
useCustomLibraryFile = !!ioLog.useCustomLibraryFile;
|
||||
runWithIOLog(ioLog, () => {
|
||||
opts = ts.parseCommandLine(ioLog.arguments, fileName => Harness.IO.readFile(fileName));
|
||||
assert.equal(opts.errors.length, 0);
|
||||
@@ -89,7 +89,7 @@ namespace RWC {
|
||||
const uniqueNames = ts.createMap<true>();
|
||||
for (const fileName of fileNames) {
|
||||
// Must maintain order, build result list while checking map
|
||||
const normalized = ts.normalizeSlashes(Harness.IO.resolvePath(fileName));
|
||||
const normalized = ts.normalizeSlashes(Harness.IO.resolvePath(fileName)!);
|
||||
if (!uniqueNames.has(normalized)) {
|
||||
uniqueNames.set(normalized, true);
|
||||
// Load the file
|
||||
@@ -99,7 +99,7 @@ namespace RWC {
|
||||
|
||||
// Add files to compilation
|
||||
for (const fileRead of ioLog.filesRead) {
|
||||
const unitName = ts.normalizeSlashes(Harness.IO.resolvePath(fileRead.path));
|
||||
const unitName = ts.normalizeSlashes(Harness.IO.resolvePath(fileRead.path)!);
|
||||
if (!uniqueNames.has(unitName) && !Harness.isDefaultLibraryFile(fileRead.path)) {
|
||||
uniqueNames.set(unitName, true);
|
||||
otherFiles.push(getHarnessCompilerInputUnit(unitName));
|
||||
@@ -134,13 +134,13 @@ namespace RWC {
|
||||
compilerOptions = compilerResult.options;
|
||||
|
||||
function getHarnessCompilerInputUnit(fileName: string): Harness.Compiler.TestFile {
|
||||
const unitName = ts.normalizeSlashes(Harness.IO.resolvePath(fileName));
|
||||
const unitName = ts.normalizeSlashes(Harness.IO.resolvePath(fileName)!);
|
||||
let content: string;
|
||||
try {
|
||||
content = Harness.IO.readFile(unitName);
|
||||
content = Harness.IO.readFile(unitName)!;
|
||||
}
|
||||
catch (e) {
|
||||
content = Harness.IO.readFile(fileName);
|
||||
content = Harness.IO.readFile(fileName)!;
|
||||
}
|
||||
return { unitName, content };
|
||||
}
|
||||
@@ -196,11 +196,11 @@ namespace RWC {
|
||||
}
|
||||
|
||||
const declContext = Harness.Compiler.prepareDeclarationCompilationContext(
|
||||
inputFiles, otherFiles, compilerResult, /*harnessSettings*/ undefined, compilerOptions, currentDirectory
|
||||
inputFiles, otherFiles, compilerResult, /*harnessSettings*/ undefined!, compilerOptions, currentDirectory // TODO: GH#18217
|
||||
);
|
||||
// Reset compilerResult before calling into `compileDeclarationFiles` so the memory from the original compilation can be freed
|
||||
compilerResult = undefined;
|
||||
const declFileCompilationResult = Harness.Compiler.compileDeclarationFiles(declContext);
|
||||
compilerResult = undefined!;
|
||||
const declFileCompilationResult = Harness.Compiler.compileDeclarationFiles(declContext)!;
|
||||
|
||||
return Harness.Compiler.iterateErrorBaseline(tsconfigFiles.concat(declFileCompilationResult.declInputFiles, declFileCompilationResult.declOtherFiles), declFileCompilationResult.declResult.diagnostics);
|
||||
}, baselineOpts);
|
||||
|
||||
@@ -19,16 +19,16 @@ namespace Harness.SourceMapRecorder {
|
||||
|
||||
interface SourceMapSpanWithDecodeErrors {
|
||||
sourceMapSpan: ts.SourceMapSpan;
|
||||
decodeErrors: string[];
|
||||
decodeErrors: string[] | undefined;
|
||||
}
|
||||
|
||||
namespace SourceMapDecoder {
|
||||
let sourceMapMappings: string;
|
||||
let sourceMapNames: string[];
|
||||
let sourceMapNames: string[] | undefined;
|
||||
let decodingIndex: number;
|
||||
let prevNameIndex: number;
|
||||
let decodeOfEncodedMapping: ts.SourceMapSpan;
|
||||
let errorDecodeOfEncodedMapping: string;
|
||||
let errorDecodeOfEncodedMapping: string | undefined;
|
||||
|
||||
export function initializeSourceMapDecoding(sourceMapData: ts.SourceMapData) {
|
||||
sourceMapMappings = sourceMapData.sourceMapMappings;
|
||||
@@ -88,7 +88,7 @@ namespace Harness.SourceMapRecorder {
|
||||
|
||||
for (; moreDigits; decodingIndex++) {
|
||||
if (createErrorIfCondition(decodingIndex >= sourceMapMappings.length, "Error in decoding base64VLQFormatDecode, past the mapping string")) {
|
||||
return;
|
||||
return undefined!; // TODO: GH#18217
|
||||
}
|
||||
|
||||
// 6 digit number
|
||||
@@ -176,7 +176,7 @@ namespace Harness.SourceMapRecorder {
|
||||
prevNameIndex += base64VLQFormatDecode();
|
||||
decodeOfEncodedMapping.nameIndex = prevNameIndex;
|
||||
// Incorrect nameIndex dont support this map
|
||||
if (createErrorIfCondition(decodeOfEncodedMapping.nameIndex < 0 || decodeOfEncodedMapping.nameIndex >= sourceMapNames.length, "Invalid name index for the source map entry")) {
|
||||
if (createErrorIfCondition(decodeOfEncodedMapping.nameIndex < 0 || decodeOfEncodedMapping.nameIndex >= sourceMapNames!.length, "Invalid name index for the source map entry")) {
|
||||
return { error: errorDecodeOfEncodedMapping, sourceMapSpan: decodeOfEncodedMapping };
|
||||
}
|
||||
}
|
||||
@@ -190,6 +190,7 @@ namespace Harness.SourceMapRecorder {
|
||||
}
|
||||
|
||||
createErrorIfCondition(/*condition*/ true, "No encoded entry found");
|
||||
return undefined!; // TODO: GH#18217
|
||||
}
|
||||
|
||||
export function hasCompletedDecoding() {
|
||||
@@ -204,7 +205,7 @@ namespace Harness.SourceMapRecorder {
|
||||
namespace SourceMapSpanWriter {
|
||||
let sourceMapRecorder: Compiler.WriterAggregator;
|
||||
let sourceMapSources: string[];
|
||||
let sourceMapNames: string[];
|
||||
let sourceMapNames: string[] | undefined;
|
||||
|
||||
let jsFile: documents.TextDocument;
|
||||
let jsLineMap: ReadonlyArray<number>;
|
||||
@@ -244,8 +245,8 @@ namespace Harness.SourceMapRecorder {
|
||||
|
||||
function getSourceMapSpanString(mapEntry: ts.SourceMapSpan, getAbsentNameIndex?: boolean) {
|
||||
let mapString = "Emitted(" + mapEntry.emittedLine + ", " + mapEntry.emittedColumn + ") Source(" + mapEntry.sourceLine + ", " + mapEntry.sourceColumn + ") + SourceIndex(" + mapEntry.sourceIndex + ")";
|
||||
if (mapEntry.nameIndex >= 0 && mapEntry.nameIndex < sourceMapNames.length) {
|
||||
mapString += " name (" + sourceMapNames[mapEntry.nameIndex] + ")";
|
||||
if (mapEntry.nameIndex! >= 0 && mapEntry.nameIndex! < sourceMapNames!.length) {
|
||||
mapString += " name (" + sourceMapNames![mapEntry.nameIndex!] + ")";
|
||||
}
|
||||
else {
|
||||
if ((mapEntry.nameIndex && mapEntry.nameIndex !== -1) || getAbsentNameIndex) {
|
||||
@@ -259,7 +260,7 @@ namespace Harness.SourceMapRecorder {
|
||||
export function recordSourceMapSpan(sourceMapSpan: ts.SourceMapSpan) {
|
||||
// verify the decoded span is same as the new span
|
||||
const decodeResult = SourceMapDecoder.decodeNextEncodedSourceMapSpan();
|
||||
let decodeErrors: string[];
|
||||
let decodeErrors: string[] | undefined;
|
||||
if (decodeResult.error
|
||||
|| decodeResult.sourceMapSpan.emittedLine !== sourceMapSpan.emittedLine
|
||||
|| decodeResult.sourceMapSpan.emittedColumn !== sourceMapSpan.emittedColumn
|
||||
@@ -345,7 +346,7 @@ namespace Harness.SourceMapRecorder {
|
||||
return markerId;
|
||||
}
|
||||
|
||||
let prevEmittedCol: number;
|
||||
let prevEmittedCol!: number;
|
||||
function iterateSpans(fn: (currentSpan: SourceMapSpanWithDecodeErrors, index: number) => void) {
|
||||
prevEmittedCol = 1;
|
||||
for (let i = 0; i < spansOnSingleLine.length; i++) {
|
||||
@@ -361,7 +362,7 @@ namespace Harness.SourceMapRecorder {
|
||||
}
|
||||
}
|
||||
|
||||
function writeSourceMapMarker(currentSpan: SourceMapSpanWithDecodeErrors, index: number, endColumn = currentSpan.sourceMapSpan.emittedColumn, endContinues?: boolean) {
|
||||
function writeSourceMapMarker(currentSpan: SourceMapSpanWithDecodeErrors, index: number, endColumn = currentSpan.sourceMapSpan.emittedColumn, endContinues = false) {
|
||||
const markerId = getMarkerId(index);
|
||||
markerIds.push(markerId);
|
||||
|
||||
@@ -421,7 +422,7 @@ namespace Harness.SourceMapRecorder {
|
||||
const jsFileText = getTextOfLine(currentJsLine, jsLineMap, jsFile.text);
|
||||
if (prevEmittedCol < jsFileText.length) {
|
||||
// There is remaining text on this line that will be part of next source span so write marker that continues
|
||||
writeSourceMapMarker(/*currentSpan*/ undefined, spansOnSingleLine.length, /*endColumn*/ jsFileText.length, /*endContinues*/ true);
|
||||
writeSourceMapMarker(/*currentSpan*/ undefined!, spansOnSingleLine.length, /*endColumn*/ jsFileText.length, /*endContinues*/ true); // TODO: GH#18217
|
||||
}
|
||||
|
||||
// Emit Source text
|
||||
@@ -440,7 +441,7 @@ namespace Harness.SourceMapRecorder {
|
||||
|
||||
for (let i = 0; i < sourceMapDataList.length; i++) {
|
||||
const sourceMapData = sourceMapDataList[i];
|
||||
let prevSourceFile: ts.SourceFile;
|
||||
let prevSourceFile: ts.SourceFile | undefined;
|
||||
let currentFile: documents.TextDocument;
|
||||
if (ts.endsWith(sourceMapData.sourceMapFile, ts.Extension.Dts)) {
|
||||
if (sourceMapDataList.length > jsFiles.length) {
|
||||
@@ -461,7 +462,7 @@ namespace Harness.SourceMapRecorder {
|
||||
|
||||
SourceMapSpanWriter.initializeSourceMapSpanWriter(sourceMapRecorder, sourceMapData, currentFile);
|
||||
for (const decodedSourceMapping of sourceMapData.sourceMapDecodedMappings) {
|
||||
const currentSourceFile = program.getSourceFile(sourceMapData.inputSourceFileNames[decodedSourceMapping.sourceIndex]);
|
||||
const currentSourceFile = program.getSourceFile(sourceMapData.inputSourceFileNames[decodedSourceMapping.sourceIndex])!;
|
||||
if (currentSourceFile !== prevSourceFile) {
|
||||
SourceMapSpanWriter.recordNewSourceFileSpan(decodedSourceMapping, currentSourceFile.text);
|
||||
prevSourceFile = currentSourceFile;
|
||||
|
||||
@@ -8,7 +8,7 @@ class Test262BaselineRunner extends RunnerBase {
|
||||
private static readonly helpersFilePath = "tests/cases/test262-harness/helpers.d.ts";
|
||||
private static readonly helperFile: Harness.Compiler.TestFile = {
|
||||
unitName: Test262BaselineRunner.helpersFilePath,
|
||||
content: Harness.IO.readFile(Test262BaselineRunner.helpersFilePath),
|
||||
content: Harness.IO.readFile(Test262BaselineRunner.helpersFilePath)!,
|
||||
};
|
||||
private static readonly testFileExtensionRegex = /\.js$/;
|
||||
private static readonly options: ts.CompilerOptions = {
|
||||
@@ -36,7 +36,7 @@ class Test262BaselineRunner extends RunnerBase {
|
||||
};
|
||||
|
||||
before(() => {
|
||||
const content = Harness.IO.readFile(filePath);
|
||||
const content = Harness.IO.readFile(filePath)!;
|
||||
const testFilename = ts.removeFileExtension(filePath).replace(/\//g, "_") + ".test";
|
||||
const testCaseContent = Harness.TestCaseParser.makeUnitsFromTest(content, testFilename);
|
||||
|
||||
@@ -49,7 +49,7 @@ class Test262BaselineRunner extends RunnerBase {
|
||||
testState = {
|
||||
filename: testFilename,
|
||||
inputFiles,
|
||||
compilerResult: undefined,
|
||||
compilerResult: undefined!, // TODO: GH#18217
|
||||
};
|
||||
|
||||
testState.compilerResult = Harness.Compiler.compileFiles(
|
||||
@@ -61,7 +61,7 @@ class Test262BaselineRunner extends RunnerBase {
|
||||
});
|
||||
|
||||
after(() => {
|
||||
testState = undefined;
|
||||
testState = undefined!;
|
||||
});
|
||||
|
||||
it("has the expected emitted code", () => {
|
||||
@@ -83,13 +83,13 @@ class Test262BaselineRunner extends RunnerBase {
|
||||
});
|
||||
|
||||
it("satisfies invariants", () => {
|
||||
const sourceFile = testState.compilerResult.program.getSourceFile(Test262BaselineRunner.getTestFilePath(testState.filename));
|
||||
const sourceFile = testState.compilerResult.program!.getSourceFile(Test262BaselineRunner.getTestFilePath(testState.filename));
|
||||
Utils.assertInvariants(sourceFile, /*parent:*/ undefined);
|
||||
});
|
||||
|
||||
it("has the expected AST", () => {
|
||||
Harness.Baseline.runBaseline(testState.filename + ".AST.txt", () => {
|
||||
const sourceFile = testState.compilerResult.program.getSourceFile(Test262BaselineRunner.getTestFilePath(testState.filename));
|
||||
const sourceFile = testState.compilerResult.program!.getSourceFile(Test262BaselineRunner.getTestFilePath(testState.filename))!;
|
||||
return Utils.sourceFileToJSON(sourceFile);
|
||||
}, Test262BaselineRunner.baselineOptions);
|
||||
});
|
||||
|
||||
@@ -34,7 +34,7 @@ class TypeWriterWalker {
|
||||
}
|
||||
|
||||
public *getSymbols(fileName: string): IterableIterator<TypeWriterSymbolResult> {
|
||||
const sourceFile = this.program.getSourceFile(fileName);
|
||||
const sourceFile = this.program.getSourceFile(fileName)!;
|
||||
this.currentSourceFile = sourceFile;
|
||||
const gen = this.visitNode(sourceFile, /*isSymbolWalk*/ true);
|
||||
for (let {done, value} = gen.next(); !done; { done, value } = gen.next()) {
|
||||
@@ -43,7 +43,7 @@ class TypeWriterWalker {
|
||||
}
|
||||
|
||||
public *getTypes(fileName: string): IterableIterator<TypeWriterTypeResult> {
|
||||
const sourceFile = this.program.getSourceFile(fileName);
|
||||
const sourceFile = this.program.getSourceFile(fileName)!;
|
||||
this.currentSourceFile = sourceFile;
|
||||
const gen = this.visitNode(sourceFile, /*isSymbolWalk*/ false);
|
||||
for (let {done, value} = gen.next(); !done; { done, value } = gen.next()) {
|
||||
@@ -69,7 +69,7 @@ class TypeWriterWalker {
|
||||
}
|
||||
}
|
||||
|
||||
private writeTypeOrSymbol(node: ts.Node, isSymbolWalk: boolean): TypeWriterResult {
|
||||
private writeTypeOrSymbol(node: ts.Node, isSymbolWalk: boolean): TypeWriterResult | undefined {
|
||||
const actualPos = ts.skipTrivia(this.currentSourceFile.text, node.pos);
|
||||
const lineAndCharacter = this.currentSourceFile.getLineAndCharacterOfPosition(actualPos);
|
||||
const sourceText = ts.getSourceTextOfNodeFromSourceFile(this.currentSourceFile, node);
|
||||
|
||||
@@ -120,7 +120,7 @@ namespace ts {
|
||||
operationWasCancelled = true;
|
||||
}
|
||||
assert.equal(cancel, operationWasCancelled);
|
||||
assert.equal(operationWasCancelled, fileNames.length > cancelAfterEmitLength);
|
||||
assert.equal(operationWasCancelled, fileNames.length > cancelAfterEmitLength!);
|
||||
assert.deepEqual(outputFileNames, fileNames.slice(0, cancelAfterEmitLength));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -10,21 +10,21 @@ namespace ts {
|
||||
`;
|
||||
it("can cancel signature help mid-request", () => {
|
||||
verifyOperationCancelledAfter(file, 4, service => // Two calls are top-level in services, one is the root type, and the second should be for the parameter type
|
||||
service.getSignatureHelpItems("file.ts", file.lastIndexOf("f")),
|
||||
service.getSignatureHelpItems("file.ts", file.lastIndexOf("f"))!,
|
||||
r => assert.exists(r.items[0])
|
||||
);
|
||||
});
|
||||
|
||||
it("can cancel find all references mid-request", () => {
|
||||
verifyOperationCancelledAfter(file, 3, service => // Two calls are top-level in services, one is the root type
|
||||
service.findReferences("file.ts", file.lastIndexOf("o")),
|
||||
service.findReferences("file.ts", file.lastIndexOf("o"))!,
|
||||
r => assert.exists(r[0].definition)
|
||||
);
|
||||
});
|
||||
|
||||
it("can cancel quick info mid-request", () => {
|
||||
verifyOperationCancelledAfter(file, 1, service => // The LS doesn't do any top-level checks on the token for quickinfo, so the first check is within the checker
|
||||
service.getQuickInfoAtPosition("file.ts", file.lastIndexOf("o")),
|
||||
service.getQuickInfoAtPosition("file.ts", file.lastIndexOf("o"))!,
|
||||
r => assert.exists(r.displayParts)
|
||||
);
|
||||
});
|
||||
@@ -52,7 +52,7 @@ namespace ts {
|
||||
placeOpenBraceOnNewLineForControlBlocks: false,
|
||||
};
|
||||
verifyOperationCancelledAfter(file, 1, service => // The LS doesn't do any top-level checks on the token for completion entry details, so the first check is within the checker
|
||||
service.getCompletionEntryDetails("file.ts", file.lastIndexOf("f"), "foo", options, /*content*/ undefined, {}),
|
||||
service.getCompletionEntryDetails("file.ts", file.lastIndexOf("f"), "foo", options, /*content*/ undefined, {})!,
|
||||
r => assert.exists(r.displayParts)
|
||||
);
|
||||
});
|
||||
|
||||
@@ -601,7 +601,7 @@ namespace ts.projectSystem {
|
||||
|
||||
const expectedOutFileName = "/a/b/dist.js";
|
||||
assert.isTrue(host.fileExists(expectedOutFileName));
|
||||
const outFileContent = host.readFile(expectedOutFileName);
|
||||
const outFileContent = host.readFile(expectedOutFileName)!;
|
||||
assert.isTrue(outFileContent.indexOf(file1.content) !== -1);
|
||||
assert.isTrue(outFileContent.indexOf(file2.content) === -1);
|
||||
assert.isTrue(outFileContent.indexOf(file3.content) === -1);
|
||||
@@ -635,14 +635,14 @@ namespace ts.projectSystem {
|
||||
// Verify js file
|
||||
const expectedOutFileName = "/root/TypeScriptProject3/TypeScriptProject3/" + outFileName;
|
||||
assert.isTrue(host.fileExists(expectedOutFileName));
|
||||
const outFileContent = host.readFile(expectedOutFileName);
|
||||
const outFileContent = host.readFile(expectedOutFileName)!;
|
||||
verifyContentHasString(outFileContent, file1.content);
|
||||
verifyContentHasString(outFileContent, `//# ${"sourceMappingURL"}=${outFileName}.map`); // Sometimes tools can sometimes see this line as a source mapping url comment, so we obfuscate it a little
|
||||
|
||||
// Verify map file
|
||||
const expectedMapFileName = expectedOutFileName + ".map";
|
||||
assert.isTrue(host.fileExists(expectedMapFileName));
|
||||
const mapFileContent = host.readFile(expectedMapFileName);
|
||||
const mapFileContent = host.readFile(expectedMapFileName)!;
|
||||
verifyContentHasString(mapFileContent, `"sources":["${inputFileName}"]`);
|
||||
|
||||
function verifyContentHasString(content: string, str: string) {
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace ts {
|
||||
assertTypeAcquisitionWithJsonNode(json, configFileName, expectedResult);
|
||||
}
|
||||
|
||||
function verifyAcquisition(actualTypeAcquisition: TypeAcquisition, expectedResult: ExpectedResult) {
|
||||
function verifyAcquisition(actualTypeAcquisition: TypeAcquisition | undefined, expectedResult: ExpectedResult) {
|
||||
const parsedTypeAcquisition = JSON.stringify(actualTypeAcquisition);
|
||||
const expectedTypeAcquisition = JSON.stringify(expectedResult.typeAcquisition);
|
||||
assert.equal(parsedTypeAcquisition, expectedTypeAcquisition);
|
||||
@@ -120,7 +120,7 @@ namespace ts {
|
||||
file: undefined,
|
||||
start: 0,
|
||||
length: 0,
|
||||
messageText: undefined
|
||||
messageText: undefined!, // TODO: GH#18217
|
||||
}
|
||||
]
|
||||
});
|
||||
@@ -215,7 +215,7 @@ namespace ts {
|
||||
file: undefined,
|
||||
start: 0,
|
||||
length: 0,
|
||||
messageText: undefined
|
||||
messageText: undefined!, // TODO: GH#18217
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace ts {
|
||||
useCaseSensitiveFileNames: () => true,
|
||||
getNewLine: () => "\n",
|
||||
fileExists: (fileName) => fileMap.has(fileName),
|
||||
readFile: (fileName) => fileMap.has(fileName) ? fileMap.get(fileName).text : undefined,
|
||||
readFile: (fileName) => fileMap.has(fileName) ? fileMap.get(fileName)!.text : undefined,
|
||||
writeFile: (fileName, text) => outputs.set(fileName, text),
|
||||
};
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace ts {
|
||||
}
|
||||
const result = refactor.extractSymbol.getRangeToExtract(file, createTextSpanFromRange(selectionRange));
|
||||
assert(result.targetRange === undefined, "failure expected");
|
||||
const sortedErrors = result.errors.map(e => <string>e.messageText).sort();
|
||||
const sortedErrors = result.errors!.map(e => <string>e.messageText).sort();
|
||||
assert.deepEqual(sortedErrors, expectedErrors.sort(), "unexpected errors");
|
||||
});
|
||||
}
|
||||
@@ -27,13 +27,14 @@ namespace ts {
|
||||
const expectedRange = t.ranges.get("extracted");
|
||||
if (expectedRange) {
|
||||
let pos: number, end: number;
|
||||
if (isArray(result.targetRange.range)) {
|
||||
pos = result.targetRange.range[0].getStart(f);
|
||||
end = lastOrUndefined(result.targetRange.range).getEnd();
|
||||
const targetRange = result.targetRange!;
|
||||
if (isArray(targetRange.range)) {
|
||||
pos = targetRange.range[0].getStart(f);
|
||||
end = last(targetRange.range).getEnd();
|
||||
}
|
||||
else {
|
||||
pos = result.targetRange.range.getStart(f);
|
||||
end = result.targetRange.range.getEnd();
|
||||
pos = targetRange.range.getStart(f);
|
||||
end = targetRange.range.getEnd();
|
||||
}
|
||||
assert.equal(pos, expectedRange.pos, "incorrect pos of range");
|
||||
assert.equal(end, expectedRange.end, "incorrect end of range");
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace ts {
|
||||
const name = s === e
|
||||
? source.charCodeAt(saved + 1) === CharacterCodes.hash ? "selection" : "extracted"
|
||||
: source.substring(s, e);
|
||||
activeRanges.push({ name, pos: text.length, end: undefined });
|
||||
activeRanges.push({ name, pos: text.length, end: undefined! }); // TODO: GH#18217
|
||||
lastPos = pos;
|
||||
continue;
|
||||
}
|
||||
@@ -45,7 +45,7 @@ namespace ts {
|
||||
else if (source.charCodeAt(pos) === CharacterCodes.bar && source.charCodeAt(pos + 1) === CharacterCodes.closeBracket) {
|
||||
text += source.substring(lastPos, pos);
|
||||
activeRanges[activeRanges.length - 1].end = text.length;
|
||||
const range = activeRanges.pop();
|
||||
const range = activeRanges.pop()!;
|
||||
if (range.name in ranges) {
|
||||
throw new Error(`Duplicate name of range ${range.name}`);
|
||||
}
|
||||
@@ -100,7 +100,7 @@ namespace ts {
|
||||
|
||||
export function testExtractSymbol(caption: string, text: string, baselineFolder: string, description: DiagnosticMessage, includeLib?: boolean) {
|
||||
const t = extractTest(text);
|
||||
const selectionRange = t.ranges.get("selection");
|
||||
const selectionRange = t.ranges.get("selection")!;
|
||||
if (!selectionRange) {
|
||||
throw new Error(`Test ${caption} does not specify selection range`);
|
||||
}
|
||||
@@ -118,7 +118,7 @@ namespace ts {
|
||||
return;
|
||||
}
|
||||
|
||||
const sourceFile = program.getSourceFile(path);
|
||||
const sourceFile = program.getSourceFile(path)!;
|
||||
const context: RefactorContext = {
|
||||
cancellationToken: { throwIfCancellationRequested: noop, isCancellationRequested: returnFalse },
|
||||
program,
|
||||
@@ -131,15 +131,15 @@ namespace ts {
|
||||
};
|
||||
const rangeToExtract = refactor.extractSymbol.getRangeToExtract(sourceFile, createTextSpanFromRange(selectionRange));
|
||||
assert.equal(rangeToExtract.errors, undefined, rangeToExtract.errors && "Range error: " + rangeToExtract.errors[0].messageText);
|
||||
const infos = refactor.extractSymbol.getAvailableActions(context);
|
||||
const actions = find(infos, info => info.description === description.message).actions;
|
||||
const infos = refactor.extractSymbol.getAvailableActions(context)!;
|
||||
const actions = find(infos, info => info.description === description.message)!.actions;
|
||||
|
||||
Harness.Baseline.runBaseline(`${baselineFolder}/${caption}${extension}`, () => {
|
||||
const data: string[] = [];
|
||||
data.push(`// ==ORIGINAL==`);
|
||||
data.push(text.replace("[#|", "/*[#|*/").replace("|]", "/*|]*/"));
|
||||
for (const action of actions) {
|
||||
const { renameLocation, edits } = refactor.extractSymbol.getEditsForAction(context, action.name);
|
||||
const { renameLocation, edits } = refactor.extractSymbol.getEditsForAction(context, action.name)!;
|
||||
assert.lengthOf(edits, 1);
|
||||
data.push(`// ==SCOPE::${action.description}==`);
|
||||
const newText = textChanges.applyChanges(sourceFile.text, edits[0].textChanges);
|
||||
@@ -157,7 +157,7 @@ namespace ts {
|
||||
const host = projectSystem.createServerHost(includeLib ? [f, projectSystem.libFile] : [f]); // libFile is expensive to parse repeatedly - only test when required
|
||||
const projectService = projectSystem.createProjectService(host);
|
||||
projectService.openClientFile(f.path);
|
||||
const program = projectService.inferredProjects[0].getLanguageService().getProgram();
|
||||
const program = projectService.inferredProjects[0].getLanguageService().getProgram()!;
|
||||
return program;
|
||||
}
|
||||
|
||||
@@ -181,8 +181,8 @@ namespace ts {
|
||||
const host = projectSystem.createServerHost([f, projectSystem.libFile]);
|
||||
const projectService = projectSystem.createProjectService(host);
|
||||
projectService.openClientFile(f.path);
|
||||
const program = projectService.inferredProjects[0].getLanguageService().getProgram();
|
||||
const sourceFile = program.getSourceFile(f.path);
|
||||
const program = projectService.inferredProjects[0].getLanguageService().getProgram()!;
|
||||
const sourceFile = program.getSourceFile(f.path)!;
|
||||
const context: RefactorContext = {
|
||||
cancellationToken: { throwIfCancellationRequested: noop, isCancellationRequested: returnFalse },
|
||||
program,
|
||||
@@ -195,7 +195,7 @@ namespace ts {
|
||||
};
|
||||
const rangeToExtract = refactor.extractSymbol.getRangeToExtract(sourceFile, createTextSpanFromRange(selectionRange));
|
||||
assert.isUndefined(rangeToExtract.errors, rangeToExtract.errors && "Range error: " + rangeToExtract.errors[0].messageText);
|
||||
const infos = refactor.extractSymbol.getAvailableActions(context);
|
||||
const infos = refactor.extractSymbol.getAvailableActions(context)!;
|
||||
assert.isUndefined(find(infos, info => info.description === description.message));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
namespace ts {
|
||||
describe("hostNewLineSupport", () => {
|
||||
function testLSWithFiles(settings: CompilerOptions, files: Harness.Compiler.TestFile[]) {
|
||||
function snapFor(path: string): IScriptSnapshot {
|
||||
function snapFor(path: string): IScriptSnapshot | undefined {
|
||||
if (path === "lib.d.ts") {
|
||||
return ScriptSnapshot.fromString("");
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace ts {
|
||||
assert.isTrue(typeAndDiagnostics && typeAndDiagnostics.diagnostics.length === 0, "no errors issued");
|
||||
|
||||
Harness.Baseline.runBaseline("JSDocParsing/TypeExpressions.parsesCorrectly." + name + ".json",
|
||||
() => Utils.sourceFileToJSON(typeAndDiagnostics.jsDocTypeExpression.type));
|
||||
() => Utils.sourceFileToJSON(typeAndDiagnostics!.jsDocTypeExpression.type));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ namespace ts {
|
||||
describe("DocComments", () => {
|
||||
function parsesCorrectly(name: string, content: string) {
|
||||
it(name, () => {
|
||||
const comment = parseIsolatedJSDocComment(content);
|
||||
const comment = parseIsolatedJSDocComment(content)!;
|
||||
if (!comment) {
|
||||
Debug.fail("Comment failed to parse entirely");
|
||||
}
|
||||
@@ -320,7 +320,7 @@ namespace ts {
|
||||
assert.equal(root.kind, SyntaxKind.SourceFile);
|
||||
const first = root.getFirstToken();
|
||||
assert.isDefined(first);
|
||||
assert.equal(first.kind, SyntaxKind.VarKeyword);
|
||||
assert.equal(first!.kind, SyntaxKind.VarKeyword);
|
||||
});
|
||||
});
|
||||
describe("getLastToken", () => {
|
||||
@@ -329,7 +329,7 @@ namespace ts {
|
||||
assert.isDefined(root);
|
||||
const last = root.getLastToken();
|
||||
assert.isDefined(last);
|
||||
assert.equal(last.kind, SyntaxKind.EndOfFileToken);
|
||||
assert.equal(last!.kind, SyntaxKind.EndOfFileToken);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/// <reference path="..\harness.ts" />
|
||||
|
||||
namespace ts {
|
||||
export function checkResolvedModule(expected: ResolvedModuleFull, actual: ResolvedModuleFull): boolean {
|
||||
export function checkResolvedModule(expected: ResolvedModuleFull | undefined, actual: ResolvedModuleFull): boolean {
|
||||
if (!expected === !actual) {
|
||||
if (expected) {
|
||||
assert.isTrue(expected.resolvedFileName === actual.resolvedFileName, `'resolvedFileName': expected '${expected.resolvedFileName}' to be equal to '${actual.resolvedFileName}'`);
|
||||
@@ -71,7 +71,7 @@ namespace ts {
|
||||
return file && file.content;
|
||||
}
|
||||
function realpath(path: string): string {
|
||||
return map.get(path).name;
|
||||
return map.get(path)!.name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,7 +332,7 @@ namespace ts {
|
||||
getSourceFile: (fileName: string, languageVersion: ScriptTarget) => {
|
||||
const path = normalizePath(combinePaths(currentDirectory, fileName));
|
||||
const file = files.get(path);
|
||||
return file && createSourceFile(fileName, file, languageVersion);
|
||||
return file ? createSourceFile(fileName, file, languageVersion) : undefined;
|
||||
},
|
||||
getDefaultLibFileName: () => "lib.d.ts",
|
||||
writeFile: notImplemented,
|
||||
@@ -420,7 +420,7 @@ export = C;
|
||||
}
|
||||
const path = getCanonicalFileName(normalizePath(combinePaths(currentDirectory, fileName)));
|
||||
const file = files.get(path);
|
||||
return file && createSourceFile(fileName, file, languageVersion);
|
||||
return file ? createSourceFile(fileName, file, languageVersion) : undefined;
|
||||
},
|
||||
getDefaultLibFileName: () => "lib.d.ts",
|
||||
writeFile: notImplemented,
|
||||
@@ -975,9 +975,9 @@ import b = require("./moduleB");
|
||||
function test(typesRoot: string, typeDirective: string, primary: boolean, initialFile: File, targetFile: File, ...otherFiles: File[]) {
|
||||
const host = createModuleResolutionHost(/*hasDirectoryExists*/ false, ...[initialFile, targetFile].concat(...otherFiles));
|
||||
const result = resolveTypeReferenceDirective(typeDirective, initialFile.name, { typeRoots: [typesRoot] }, host);
|
||||
assert(result.resolvedTypeReferenceDirective.resolvedFileName !== undefined, "expected type directive to be resolved");
|
||||
assert.equal(result.resolvedTypeReferenceDirective.resolvedFileName, targetFile.name, "unexpected result of type reference resolution");
|
||||
assert.equal(result.resolvedTypeReferenceDirective.primary, primary, "unexpected 'primary' value");
|
||||
assert(result.resolvedTypeReferenceDirective!.resolvedFileName !== undefined, "expected type directive to be resolved");
|
||||
assert.equal(result.resolvedTypeReferenceDirective!.resolvedFileName, targetFile.name, "unexpected result of type reference resolution");
|
||||
assert.equal(result.resolvedTypeReferenceDirective!.primary, primary, "unexpected 'primary' value");
|
||||
}
|
||||
|
||||
it("Can be resolved from primary location", () => {
|
||||
@@ -1111,10 +1111,7 @@ import b = require("./moduleB");
|
||||
getNewLine: () => "\r\n",
|
||||
useCaseSensitiveFileNames: () => false,
|
||||
readFile: fileName => fileName === file.fileName ? file.text : undefined,
|
||||
resolveModuleNames() {
|
||||
assert(false, "resolveModuleNames should not be called");
|
||||
return undefined;
|
||||
}
|
||||
resolveModuleNames: notImplemented,
|
||||
};
|
||||
createProgram([f.name], {}, compilerHost);
|
||||
});
|
||||
@@ -1145,7 +1142,7 @@ import b = require("./moduleB");
|
||||
readFile: fileName => fileName === file.fileName ? file.text : undefined,
|
||||
resolveModuleNames(moduleNames: string[], _containingFile: string) {
|
||||
assert.deepEqual(moduleNames, ["fs"]);
|
||||
return [undefined];
|
||||
return [undefined!]; // TODO: GH#18217
|
||||
}
|
||||
};
|
||||
createProgram([f.name], {}, compilerHost);
|
||||
|
||||
@@ -136,7 +136,7 @@ namespace ts.projectSystem {
|
||||
projectService.openClientFile(file1.path);
|
||||
{
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
const configuredProject = forEach(projectService.synchronizeProjectList([]), f => f.info.projectName === corruptedConfig.path && f);
|
||||
const configuredProject = find(projectService.synchronizeProjectList([]), f => f.info!.projectName === corruptedConfig.path)!;
|
||||
assert.isTrue(configuredProject !== undefined, "should find configured project");
|
||||
checkProjectErrors(configuredProject, []);
|
||||
const projectErrors = configuredProjectAt(projectService, 0).getAllProjectErrors();
|
||||
@@ -144,13 +144,13 @@ namespace ts.projectSystem {
|
||||
"'{' expected."
|
||||
]);
|
||||
assert.isNotNull(projectErrors[0].file);
|
||||
assert.equal(projectErrors[0].file.fileName, corruptedConfig.path);
|
||||
assert.equal(projectErrors[0].file!.fileName, corruptedConfig.path);
|
||||
}
|
||||
// fix config and trigger watcher
|
||||
host.reloadFS([file1, file2, correctConfig]);
|
||||
{
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
const configuredProject = forEach(projectService.synchronizeProjectList([]), f => f.info.projectName === corruptedConfig.path && f);
|
||||
const configuredProject = find(projectService.synchronizeProjectList([]), f => f.info!.projectName === corruptedConfig.path)!;
|
||||
assert.isTrue(configuredProject !== undefined, "should find configured project");
|
||||
checkProjectErrors(configuredProject, []);
|
||||
const projectErrors = configuredProjectAt(projectService, 0).getAllProjectErrors();
|
||||
@@ -181,7 +181,7 @@ namespace ts.projectSystem {
|
||||
projectService.openClientFile(file1.path);
|
||||
{
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
const configuredProject = forEach(projectService.synchronizeProjectList([]), f => f.info.projectName === corruptedConfig.path && f);
|
||||
const configuredProject = find(projectService.synchronizeProjectList([]), f => f.info!.projectName === corruptedConfig.path)!;
|
||||
assert.isTrue(configuredProject !== undefined, "should find configured project");
|
||||
checkProjectErrors(configuredProject, []);
|
||||
const projectErrors = configuredProjectAt(projectService, 0).getAllProjectErrors();
|
||||
@@ -191,7 +191,7 @@ namespace ts.projectSystem {
|
||||
host.reloadFS([file1, file2, corruptedConfig]);
|
||||
{
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
const configuredProject = forEach(projectService.synchronizeProjectList([]), f => f.info.projectName === corruptedConfig.path && f);
|
||||
const configuredProject = find(projectService.synchronizeProjectList([]), f => f.info!.projectName === corruptedConfig.path)!;
|
||||
assert.isTrue(configuredProject !== undefined, "should find configured project");
|
||||
checkProjectErrors(configuredProject, []);
|
||||
const projectErrors = configuredProjectAt(projectService, 0).getAllProjectErrors();
|
||||
@@ -199,7 +199,7 @@ namespace ts.projectSystem {
|
||||
"'{' expected."
|
||||
]);
|
||||
assert.isNotNull(projectErrors[0].file);
|
||||
assert.equal(projectErrors[0].file.fileName, corruptedConfig.path);
|
||||
assert.equal(projectErrors[0].file!.fileName, corruptedConfig.path);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
const vfsys = new vfs.FileSystem(false, { files: { "/lib.d.ts": TestFSWithWatch.libFile.content! } });
|
||||
const vfsys = new vfs.FileSystem(false, { files: { "/lib.d.ts": TestFSWithWatch.libFile.content } });
|
||||
files.forEach((v, k) => {
|
||||
vfsys.mkdirpSync(getDirectoryPath(k));
|
||||
vfsys.writeFileSync(k, v);
|
||||
|
||||
@@ -6,7 +6,7 @@ describe("Public APIs", () => {
|
||||
const api = `api/${fileName}`;
|
||||
let fileContent: string;
|
||||
before(() => {
|
||||
fileContent = Harness.IO.readFile(builtFile);
|
||||
fileContent = Harness.IO.readFile(builtFile)!;
|
||||
});
|
||||
|
||||
it("should be acknowledged when they change", () => {
|
||||
|
||||
@@ -93,7 +93,7 @@ namespace ts {
|
||||
newLength = this.program.length;
|
||||
break;
|
||||
default:
|
||||
Debug.assert(false, "Unexpected change");
|
||||
return Debug.fail("Unexpected change");
|
||||
}
|
||||
|
||||
return createTextChangeRange(oldSpan, newLength);
|
||||
@@ -114,7 +114,7 @@ namespace ts {
|
||||
if (oldFile && oldFile.redirectInfo) {
|
||||
oldFile = oldFile.redirectInfo.unredirected;
|
||||
}
|
||||
if (oldFile && oldFile.sourceText.getVersion() === t.text.getVersion()) {
|
||||
if (oldFile && oldFile.sourceText!.getVersion() === t.text.getVersion()) {
|
||||
return oldFile;
|
||||
}
|
||||
}
|
||||
@@ -126,7 +126,7 @@ namespace ts {
|
||||
trace: s => trace.push(s),
|
||||
getTrace: () => trace,
|
||||
getSourceFile(fileName): SourceFile {
|
||||
return files.get(fileName);
|
||||
return files.get(fileName)!;
|
||||
},
|
||||
getDefaultLibFileName(): string {
|
||||
return "lib.d.ts";
|
||||
@@ -156,7 +156,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function newProgram(texts: NamedSourceText[], rootNames: string[], options: CompilerOptions): ProgramWithSourceTexts {
|
||||
const host = createTestCompilerHost(texts, options.target);
|
||||
const host = createTestCompilerHost(texts, options.target!);
|
||||
const program = <ProgramWithSourceTexts>createProgram(rootNames, options, host);
|
||||
program.sourceTexts = texts;
|
||||
program.host = host;
|
||||
@@ -165,10 +165,10 @@ namespace ts {
|
||||
|
||||
export function updateProgram(oldProgram: ProgramWithSourceTexts, rootNames: ReadonlyArray<string>, options: CompilerOptions, updater: (files: NamedSourceText[]) => void, newTexts?: NamedSourceText[]) {
|
||||
if (!newTexts) {
|
||||
newTexts = oldProgram.sourceTexts.slice(0);
|
||||
newTexts = oldProgram.sourceTexts!.slice(0);
|
||||
}
|
||||
updater(newTexts);
|
||||
const host = createTestCompilerHost(newTexts, options.target, oldProgram);
|
||||
const host = createTestCompilerHost(newTexts, options.target!, oldProgram);
|
||||
const program = <ProgramWithSourceTexts>createProgram(rootNames, options, host, oldProgram);
|
||||
program.sourceTexts = newTexts;
|
||||
program.host = host;
|
||||
@@ -191,16 +191,16 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
function checkCache<T>(caption: string, program: Program, fileName: string, expectedContent: Map<T>, getCache: (f: SourceFile) => Map<T>, entryChecker: (expected: T, original: T) => boolean): void {
|
||||
function checkCache<T>(caption: string, program: Program, fileName: string, expectedContent: Map<T> | undefined, getCache: (f: SourceFile) => Map<T> | undefined, entryChecker: (expected: T, original: T) => boolean): void {
|
||||
const file = program.getSourceFile(fileName);
|
||||
assert.isTrue(file !== undefined, `cannot find file ${fileName}`);
|
||||
const cache = getCache(file);
|
||||
const cache = getCache(file!);
|
||||
if (expectedContent === undefined) {
|
||||
assert.isTrue(cache === undefined, `expected ${caption} to be undefined`);
|
||||
}
|
||||
else {
|
||||
assert.isTrue(cache !== undefined, `expected ${caption} to be set`);
|
||||
assert.isTrue(mapsAreEqual(expectedContent, cache, entryChecker), `contents of ${caption} did not match the expected contents.`);
|
||||
assert.isTrue(mapsAreEqual(expectedContent, cache!, entryChecker), `contents of ${caption} did not match the expected contents.`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,7 +210,7 @@ namespace ts {
|
||||
if (!left || !right) return false;
|
||||
const someInLeftHasNoMatch = forEachEntry(left, (leftValue, leftKey) => {
|
||||
if (!right.has(leftKey)) return true;
|
||||
const rightValue = right.get(leftKey);
|
||||
const rightValue = right.get(leftKey)!;
|
||||
return !(valuesAreEqual ? valuesAreEqual(leftValue, rightValue) : leftValue === rightValue);
|
||||
});
|
||||
if (someInLeftHasNoMatch) return false;
|
||||
@@ -218,11 +218,11 @@ namespace ts {
|
||||
return !someInRightHasNoMatch;
|
||||
}
|
||||
|
||||
function checkResolvedModulesCache(program: Program, fileName: string, expectedContent: Map<ResolvedModule>): void {
|
||||
function checkResolvedModulesCache(program: Program, fileName: string, expectedContent: Map<ResolvedModule | undefined> | undefined): void {
|
||||
checkCache("resolved modules", program, fileName, expectedContent, f => f.resolvedModules, checkResolvedModule);
|
||||
}
|
||||
|
||||
function checkResolvedTypeDirectivesCache(program: Program, fileName: string, expectedContent: Map<ResolvedTypeReferenceDirective>): void {
|
||||
function checkResolvedTypeDirectivesCache(program: Program, fileName: string, expectedContent: Map<ResolvedTypeReferenceDirective> | undefined): void {
|
||||
checkCache("resolved type directives", program, fileName, expectedContent, f => f.resolvedTypeReferenceDirectiveNames, checkResolvedTypeDirective);
|
||||
}
|
||||
|
||||
@@ -399,7 +399,7 @@ namespace ts {
|
||||
const program2 = updateProgram(program1, ["/a.ts"], options, files => {
|
||||
files[0].text = files[0].text.updateProgram('import * as aa from "a";');
|
||||
});
|
||||
assert.isDefined(program2.getSourceFile("/a.ts").resolvedModules.get("a"), "'a' is not an unresolved module after re-use");
|
||||
assert.isDefined(program2.getSourceFile("/a.ts")!.resolvedModules!.get("a"), "'a' is not an unresolved module after re-use");
|
||||
});
|
||||
|
||||
it("resolved type directives cache follows type directives", () => {
|
||||
@@ -896,7 +896,7 @@ namespace ts {
|
||||
) {
|
||||
const actual = isProgramUptoDate(
|
||||
program, newRootFileNames, newOptions,
|
||||
path => program.getSourceFileByPath(path).version, /*fileExists*/ returnFalse,
|
||||
path => program.getSourceFileByPath(path)!.version, /*fileExists*/ returnFalse,
|
||||
/*hasInvalidatedResolution*/ returnFalse,
|
||||
/*hasChangedAutomaticTypeDirectiveNames*/ false
|
||||
);
|
||||
@@ -916,7 +916,7 @@ namespace ts {
|
||||
|
||||
function verifyProgramWithConfigFile(system: System, configFileName: string) {
|
||||
const program = createWatchProgram(createWatchCompilerHostOfConfigFile(configFileName, {}, system)).getCurrentProgram().getProgram();
|
||||
const { fileNames, options } = parseConfigFileWithSystem(configFileName, {}, system, notImplemented);
|
||||
const { fileNames, options } = parseConfigFileWithSystem(configFileName, {}, system, notImplemented)!; // TODO: GH#18217
|
||||
verifyProgramIsUptoDate(program, fileNames, options);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ describe("Colorization", () => {
|
||||
function identifier(text: string, position?: number) { return createClassification(text, ts.TokenClass.Identifier, position); }
|
||||
function numberLiteral(text: string, position?: number) { return createClassification(text, ts.TokenClass.NumberLiteral, position); }
|
||||
function stringLiteral(text: string, position?: number) { return createClassification(text, ts.TokenClass.StringLiteral, position); }
|
||||
function finalEndOfLineState(value: number): ClassificationEntry { return { value, classification: undefined, position: 0 }; }
|
||||
function finalEndOfLineState(value: number): ClassificationEntry { return { value, classification: undefined!, position: 0 }; } // TODO: GH#18217
|
||||
function createClassification(value: string, classification: ts.TokenClass, position?: number): ClassificationEntry {
|
||||
return { value, classification, position };
|
||||
}
|
||||
@@ -48,7 +48,7 @@ describe("Colorization", () => {
|
||||
const actualEntryPosition = expectedEntry.position !== undefined ? expectedEntry.position : text.indexOf(expectedEntry.value);
|
||||
assert(actualEntryPosition >= 0, "token: '" + expectedEntry.value + "' does not exit in text: '" + text + "'.");
|
||||
|
||||
const actualEntry = getEntryAtPosition(result, actualEntryPosition);
|
||||
const actualEntry = getEntryAtPosition(result, actualEntryPosition)!;
|
||||
|
||||
assert(actualEntry, "Could not find classification entry for '" + expectedEntry.value + "' at position: " + actualEntryPosition);
|
||||
assert.equal(actualEntry.classification, expectedEntry.classification, "Classification class does not match expected. Expected: " + ts.TokenClass[expectedEntry.classification] + ", Actual: " + ts.TokenClass[actualEntry.classification]);
|
||||
@@ -351,7 +351,7 @@ describe("Colorization", () => {
|
||||
pos += lastLength;
|
||||
lastLength = val.length;
|
||||
}
|
||||
return ts.lastOrUndefined(vals);
|
||||
return ts.last(vals);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -321,7 +321,7 @@ describe("PatternMatcher", () => {
|
||||
});
|
||||
|
||||
function assertSegmentMatch(candidate: string, pattern: string, expected: ts.PatternMatch | undefined): void {
|
||||
assert.deepEqual(ts.createPatternMatcher(pattern).getMatchForLastSegmentOfPattern(candidate), expected);
|
||||
assert.deepEqual(ts.createPatternMatcher(pattern)!.getMatchForLastSegmentOfPattern(candidate), expected);
|
||||
}
|
||||
|
||||
function assertInvalidPattern(pattern: string) {
|
||||
@@ -329,7 +329,7 @@ describe("PatternMatcher", () => {
|
||||
}
|
||||
|
||||
function assertFullMatch(dottedContainer: string, candidate: string, pattern: string, expected: ts.PatternMatch | undefined): void {
|
||||
assert.deepEqual(ts.createPatternMatcher(pattern).getFullMatch(dottedContainer.split("."), candidate), expected);
|
||||
assert.deepEqual(ts.createPatternMatcher(pattern)!.getFullMatch(dottedContainer.split("."), candidate), expected);
|
||||
}
|
||||
|
||||
function spanListToSubstrings(identifier: string, spans: ts.TextSpan[]) {
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace ts.server {
|
||||
write(s): void { lastWrittenToHost = s; },
|
||||
readFile: () => undefined,
|
||||
writeFile: noop,
|
||||
resolvePath(): string { return void 0; },
|
||||
resolvePath(): string { return undefined!; }, // TODO: GH#18217
|
||||
fileExists: () => false,
|
||||
directoryExists: () => false,
|
||||
getDirectories: () => [],
|
||||
@@ -47,7 +47,7 @@ namespace ts.server {
|
||||
cancellationToken: nullCancellationToken,
|
||||
useSingleInferredProject: false,
|
||||
useInferredProjectPerProjectRoot: false,
|
||||
typingsInstaller: undefined,
|
||||
typingsInstaller: undefined!, // TODO: GH#18217
|
||||
byteLength: Utils.byteLength,
|
||||
hrtime: process.hrtime,
|
||||
logger: projectSystem.nullLogger,
|
||||
@@ -81,7 +81,7 @@ namespace ts.server {
|
||||
seq: 0,
|
||||
type: "request",
|
||||
arguments: {
|
||||
file: undefined
|
||||
file: undefined! // TODO: GH#18217
|
||||
}
|
||||
};
|
||||
|
||||
@@ -441,7 +441,7 @@ namespace ts.server {
|
||||
lastSent: protocol.Message;
|
||||
private exceptionRaisingHandler(_request: protocol.Request): { response?: any, responseRequired: boolean } {
|
||||
f1();
|
||||
return;
|
||||
return Debug.fail(); // unreachable, throw to make compiler happy
|
||||
function f1() {
|
||||
throw new Error("myMessage");
|
||||
}
|
||||
@@ -453,7 +453,7 @@ namespace ts.server {
|
||||
cancellationToken: nullCancellationToken,
|
||||
useSingleInferredProject: false,
|
||||
useInferredProjectPerProjectRoot: false,
|
||||
typingsInstaller: undefined,
|
||||
typingsInstaller: undefined!, // TODO: GH#18217
|
||||
byteLength: Utils.byteLength,
|
||||
hrtime: process.hrtime,
|
||||
logger: projectSystem.nullLogger,
|
||||
@@ -500,7 +500,7 @@ namespace ts.server {
|
||||
cancellationToken: nullCancellationToken,
|
||||
useSingleInferredProject: false,
|
||||
useInferredProjectPerProjectRoot: false,
|
||||
typingsInstaller: undefined,
|
||||
typingsInstaller: undefined!, // TODO: GH#18217
|
||||
byteLength: Utils.byteLength,
|
||||
hrtime: process.hrtime,
|
||||
logger: projectSystem.nullLogger,
|
||||
@@ -568,7 +568,7 @@ namespace ts.server {
|
||||
cancellationToken: nullCancellationToken,
|
||||
useSingleInferredProject: false,
|
||||
useInferredProjectPerProjectRoot: false,
|
||||
typingsInstaller: undefined,
|
||||
typingsInstaller: undefined!, // TODO: GH#18217
|
||||
byteLength: Utils.byteLength,
|
||||
hrtime: process.hrtime,
|
||||
logger: projectSystem.nullLogger,
|
||||
@@ -604,7 +604,7 @@ namespace ts.server {
|
||||
|
||||
consumeQueue() {
|
||||
while (this.queue.length > 0) {
|
||||
const elem = this.queue.pop();
|
||||
const elem = this.queue.pop()!;
|
||||
this.handleRequest(elem);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ namespace ts {
|
||||
unitName: "main.ts",
|
||||
content: source
|
||||
}], [], {}, {}, "/");
|
||||
const file = result.program.getSourceFile("main.ts");
|
||||
const checker = result.program.getTypeChecker();
|
||||
const file = result.program!.getSourceFile("main.ts")!;
|
||||
const checker = result.program!.getTypeChecker();
|
||||
verifier(file, checker);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
namespace ts {
|
||||
describe("textChanges", () => {
|
||||
function findChild(name: string, n: Node) {
|
||||
return find(n);
|
||||
return find(n)!;
|
||||
|
||||
function find(node: Node): Node {
|
||||
function find(node: Node): Node | undefined {
|
||||
if (isDeclaration(node) && node.name && isIdentifier(node.name) && node.name.escapedText === name) {
|
||||
return node;
|
||||
}
|
||||
@@ -88,7 +88,7 @@ namespace M
|
||||
}
|
||||
}`;
|
||||
runSingleFileTest("extractMethodLike", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
|
||||
const statements = (<FunctionDeclaration>findChild("foo", sourceFile)).body.statements.slice(1);
|
||||
const statements = (<FunctionDeclaration>findChild("foo", sourceFile)).body!.statements.slice(1);
|
||||
const newFunction = createFunctionDeclaration(
|
||||
/*decorators*/ undefined,
|
||||
/*modifiers*/ undefined,
|
||||
@@ -105,11 +105,11 @@ namespace M
|
||||
// replace statements with return statement
|
||||
const newStatement = createReturn(
|
||||
createCall(
|
||||
/*expression*/ newFunction.name,
|
||||
/*expression*/ newFunction.name!,
|
||||
/*typeArguments*/ undefined,
|
||||
/*argumentsArray*/ emptyArray
|
||||
));
|
||||
changeTracker.replaceNodeRange(sourceFile, statements[0], lastOrUndefined(statements), newStatement, { suffix: newLineCharacter });
|
||||
changeTracker.replaceNodeRange(sourceFile, statements[0], last(statements), newStatement, { suffix: newLineCharacter });
|
||||
});
|
||||
}
|
||||
{
|
||||
|
||||
@@ -139,7 +139,7 @@ namespace ts {
|
||||
return (sourceFile: SourceFile) => {
|
||||
const result = getMutableClone(sourceFile);
|
||||
result.statements = createNodeArray([
|
||||
createClassDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, "Foo", /*typeParameters*/ undefined, /*heritageClauses*/ undefined, /*members*/ undefined),
|
||||
createClassDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, "Foo", /*typeParameters*/ undefined, /*heritageClauses*/ undefined, /*members*/ undefined!), // TODO: GH#18217
|
||||
createModuleDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, createIdentifier("Foo"), createModuleBlock([createEmptyStatement()]))
|
||||
]);
|
||||
return result;
|
||||
@@ -266,7 +266,7 @@ namespace ts {
|
||||
function baselineDeclarationTransform(text: string, opts: TranspileOptions) {
|
||||
const fs = vfs.createFromFileSystem(Harness.IO, /*caseSensitive*/ true, { documents: [new documents.TextDocument("/.src/index.ts", text)] });
|
||||
const host = new fakes.CompilerHost(fs, opts.compilerOptions);
|
||||
const program = createProgram(["/.src/index.ts"], opts.compilerOptions, host);
|
||||
const program = createProgram(["/.src/index.ts"], opts.compilerOptions!, host);
|
||||
program.emit(program.getSourceFiles()[1], (p, s, bom) => host.writeFile(p, s, bom), /*cancellationToken*/ undefined, /*onlyDts*/ true, opts.transformers);
|
||||
return fs.readFileSync("/.src/index.d.ts").toString();
|
||||
}
|
||||
|
||||
@@ -53,20 +53,20 @@ namespace ts {
|
||||
});
|
||||
|
||||
after(() => {
|
||||
transpileResult = undefined;
|
||||
oldTranspileResult = undefined;
|
||||
oldTranspileDiagnostics = undefined;
|
||||
transpileResult = undefined!;
|
||||
oldTranspileResult = undefined!;
|
||||
oldTranspileDiagnostics = undefined!;
|
||||
});
|
||||
|
||||
it("Correct errors for " + justName, () => {
|
||||
Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ".errors.txt"), () => {
|
||||
if (transpileResult.diagnostics.length === 0) {
|
||||
if (transpileResult.diagnostics!.length === 0) {
|
||||
/* tslint:disable:no-null-keyword */
|
||||
return null;
|
||||
/* tslint:enable:no-null-keyword */
|
||||
}
|
||||
|
||||
return Harness.Compiler.getErrorBaseline(toBeCompiled, transpileResult.diagnostics);
|
||||
return Harness.Compiler.getErrorBaseline(toBeCompiled, transpileResult.diagnostics!);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -171,7 +171,7 @@ namespace ts.tscWatch {
|
||||
assert.equal(host.exitCode, expectedExitCode);
|
||||
}
|
||||
|
||||
function getDiagnosticOfFileFrom(file: SourceFile, text: string, start: number, length: number, message: DiagnosticMessage): Diagnostic {
|
||||
function getDiagnosticOfFileFrom(file: SourceFile | undefined, text: string, start: number | undefined, length: number | undefined, message: DiagnosticMessage): Diagnostic {
|
||||
return {
|
||||
file,
|
||||
start,
|
||||
@@ -205,7 +205,7 @@ namespace ts.tscWatch {
|
||||
|
||||
function getUnknownCompilerOption(program: Program, configFile: File, option: string) {
|
||||
const quotedOption = `"${option}"`;
|
||||
return getDiagnosticOfFile(program.getCompilerOptions().configFile, configFile.content.indexOf(quotedOption), quotedOption.length, Diagnostics.Unknown_compiler_option_0, option);
|
||||
return getDiagnosticOfFile(program.getCompilerOptions().configFile!, configFile.content.indexOf(quotedOption), quotedOption.length, Diagnostics.Unknown_compiler_option_0, option);
|
||||
}
|
||||
|
||||
function getDiagnosticOfFileFromProgram(program: Program, filePath: string, start: number, length: number, message: DiagnosticMessage, ..._args: (string | number)[]): Diagnostic {
|
||||
@@ -215,7 +215,7 @@ namespace ts.tscWatch {
|
||||
text = formatStringFromArgs(text, arguments, 5);
|
||||
}
|
||||
|
||||
return getDiagnosticOfFileFrom(program.getSourceFileByPath(toPath(filePath, program.getCurrentDirectory(), s => s.toLowerCase())),
|
||||
return getDiagnosticOfFileFrom(program.getSourceFileByPath(toPath(filePath, program.getCurrentDirectory(), s => s.toLowerCase()))!,
|
||||
text, start, length, message);
|
||||
}
|
||||
|
||||
@@ -1101,8 +1101,8 @@ namespace ts.tscWatch {
|
||||
const host = createWatchedSystem(files);
|
||||
const watch = createWatchOfConfigFile(configFile.path, host);
|
||||
const errors = () => [
|
||||
getDiagnosticOfFile(watch().getCompilerOptions().configFile, configFile.content.indexOf('"allowJs"'), '"allowJs"'.length, Diagnostics.Option_0_cannot_be_specified_with_option_1, "allowJs", "declaration"),
|
||||
getDiagnosticOfFile(watch().getCompilerOptions().configFile, configFile.content.indexOf('"declaration"'), '"declaration"'.length, Diagnostics.Option_0_cannot_be_specified_with_option_1, "allowJs", "declaration")
|
||||
getDiagnosticOfFile(watch().getCompilerOptions().configFile!, configFile.content.indexOf('"allowJs"'), '"allowJs"'.length, Diagnostics.Option_0_cannot_be_specified_with_option_1, "allowJs", "declaration"),
|
||||
getDiagnosticOfFile(watch().getCompilerOptions().configFile!, configFile.content.indexOf('"declaration"'), '"declaration"'.length, Diagnostics.Option_0_cannot_be_specified_with_option_1, "allowJs", "declaration")
|
||||
];
|
||||
const intialErrors = errors();
|
||||
checkOutputErrorsInitial(host, intialErrors);
|
||||
@@ -1112,8 +1112,8 @@ namespace ts.tscWatch {
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
const nowErrors = errors();
|
||||
checkOutputErrorsIncremental(host, nowErrors);
|
||||
assert.equal(nowErrors[0].start, intialErrors[0].start - configFileContentComment.length);
|
||||
assert.equal(nowErrors[1].start, intialErrors[1].start - configFileContentComment.length);
|
||||
assert.equal(nowErrors[0].start, intialErrors[0].start! - configFileContentComment.length);
|
||||
assert.equal(nowErrors[1].start, intialErrors[1].start! - configFileContentComment.length);
|
||||
});
|
||||
|
||||
it("should not trigger recompilation because of program emit", () => {
|
||||
@@ -1409,7 +1409,7 @@ namespace ts.tscWatch {
|
||||
}
|
||||
|
||||
function getFile(fileName: string) {
|
||||
return find(files, file => file.path === fileName);
|
||||
return find(files, file => file.path === fileName)!;
|
||||
}
|
||||
|
||||
function verifyAffectedAllFiles() {
|
||||
@@ -2252,7 +2252,7 @@ declare module "fs" {
|
||||
const disableConsoleClear = options.diagnostics || options.extendedDiagnostics || options.preserveWatchOutput;
|
||||
const host = createWatchedSystem(files);
|
||||
createWatchOfFilesAndCompilerOptions([file.path], host, options);
|
||||
checkOutputErrorsInitial(host, emptyArray, disableConsoleClear, options.extendedDiagnostics && [
|
||||
checkOutputErrorsInitial(host, emptyArray, disableConsoleClear, options.extendedDiagnostics ? [
|
||||
"Current directory: / CaseSensitiveFileNames: false\n",
|
||||
"Synchronizing program\n",
|
||||
"CreatingProgramWith::\n",
|
||||
@@ -2260,21 +2260,21 @@ declare module "fs" {
|
||||
" options: {\"extendedDiagnostics\":true}\n",
|
||||
"FileWatcher:: Added:: WatchInfo: f.ts 250 Source file\n",
|
||||
"FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 250 Source file\n"
|
||||
]);
|
||||
] : undefined);
|
||||
|
||||
file.content = "//";
|
||||
host.reloadFS(files);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
checkOutputErrorsIncremental(host, emptyArray, disableConsoleClear, options.extendedDiagnostics && [
|
||||
checkOutputErrorsIncremental(host, emptyArray, disableConsoleClear, options.extendedDiagnostics ? [
|
||||
"FileWatcher:: Triggered with /f.ts1:: WatchInfo: f.ts 250 Source file\n",
|
||||
"Scheduling update\n",
|
||||
"Elapsed:: 0ms FileWatcher:: Triggered with /f.ts1:: WatchInfo: f.ts 250 Source file\n"
|
||||
], options.extendedDiagnostics && [
|
||||
] : undefined, options.extendedDiagnostics ? [
|
||||
"Synchronizing program\n",
|
||||
"CreatingProgramWith::\n",
|
||||
" roots: [\"f.ts\"]\n",
|
||||
" options: {\"extendedDiagnostics\":true}\n"
|
||||
]);
|
||||
] : undefined);
|
||||
}
|
||||
|
||||
it("without --diagnostics or --extendedDiagnostics", () => {
|
||||
|
||||
@@ -135,11 +135,12 @@ namespace ts {
|
||||
const parsed = parseConfigFileTextToJson("/apath/tsconfig.json", "invalid");
|
||||
assert.deepEqual(parsed.config, { invalid: undefined });
|
||||
const expected = createCompilerDiagnostic(Diagnostics._0_expected, "{");
|
||||
assert.equal(parsed.error.messageText, expected.messageText);
|
||||
assert.equal(parsed.error.category, expected.category);
|
||||
assert.equal(parsed.error.code, expected.code);
|
||||
assert.equal(parsed.error.start, 0);
|
||||
assert.equal(parsed.error.length, "invalid".length);
|
||||
const error = parsed.error!;
|
||||
assert.equal(error.messageText, expected.messageText);
|
||||
assert.equal(error.category, expected.category);
|
||||
assert.equal(error.code, expected.code);
|
||||
assert.equal(error.start, 0);
|
||||
assert.equal(error.length, "invalid".length);
|
||||
});
|
||||
|
||||
it("returns object when users correctly specify library", () => {
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace ts.projectSystem {
|
||||
msg: noop,
|
||||
startGroup: noop,
|
||||
endGroup: noop,
|
||||
getLogFileName: (): string => undefined
|
||||
getLogFileName: () => undefined,
|
||||
};
|
||||
|
||||
export class TestTypingsInstaller extends TI.TypingsInstaller implements server.ITypingsInstaller {
|
||||
@@ -189,7 +189,7 @@ namespace ts.projectSystem {
|
||||
}
|
||||
|
||||
getEvent<T extends server.ProjectServiceEvent>(eventName: T["eventName"]): T["data"] {
|
||||
let eventData: T["data"];
|
||||
let eventData: T["data"] | undefined;
|
||||
filterMutate(this.events, e => {
|
||||
if (e.eventName === eventName) {
|
||||
if (eventData !== undefined) {
|
||||
@@ -200,8 +200,7 @@ namespace ts.projectSystem {
|
||||
}
|
||||
return true;
|
||||
});
|
||||
assert.isDefined(eventData);
|
||||
return eventData;
|
||||
return Debug.assertDefined(eventData);
|
||||
}
|
||||
|
||||
hasZeroEvent<T extends server.ProjectServiceEvent>(eventName: T["eventName"]) {
|
||||
@@ -216,7 +215,7 @@ namespace ts.projectSystem {
|
||||
|
||||
assertProjectInfoTelemetryEvent(partial: Partial<server.ProjectInfoTelemetryEventData>, configFile = "/tsconfig.json"): void {
|
||||
assert.deepEqual<server.ProjectInfoTelemetryEventData>(this.getEvent<server.ProjectInfoTelemetryEvent>(server.ProjectInfoTelemetryEvent), {
|
||||
projectId: sys.createSHA256Hash(configFile),
|
||||
projectId: sys.createSHA256Hash!(configFile),
|
||||
fileStats: fileStats({ ts: 1 }),
|
||||
compilerOptions: {},
|
||||
extends: false,
|
||||
@@ -294,7 +293,7 @@ namespace ts.projectSystem {
|
||||
cancellationToken: server.nullCancellationToken,
|
||||
useSingleInferredProject: false,
|
||||
useInferredProjectPerProjectRoot: false,
|
||||
typingsInstaller: undefined,
|
||||
typingsInstaller: undefined!, // TODO: GH#18217
|
||||
byteLength: Utils.byteLength,
|
||||
hrtime: process.hrtime,
|
||||
logger: opts.logger || nullLogger,
|
||||
@@ -336,7 +335,7 @@ namespace ts.projectSystem {
|
||||
const cancellationToken = parameters.cancellationToken || server.nullCancellationToken;
|
||||
const logger = parameters.logger || nullLogger;
|
||||
const useSingleInferredProject = parameters.useSingleInferredProject !== undefined ? parameters.useSingleInferredProject : false;
|
||||
return new TestProjectService(host, logger, cancellationToken, useSingleInferredProject, parameters.typingsInstaller, parameters.eventHandler, options);
|
||||
return new TestProjectService(host, logger, cancellationToken, useSingleInferredProject, parameters.typingsInstaller!, parameters.eventHandler!, options); // TODO: GH#18217
|
||||
}
|
||||
|
||||
export function checkNumberOfConfiguredProjects(projectService: server.ProjectService, expected: number) {
|
||||
@@ -404,7 +403,7 @@ namespace ts.projectSystem {
|
||||
}
|
||||
|
||||
function checkOpenFiles(projectService: server.ProjectService, expectedFiles: File[]) {
|
||||
checkArray("Open files", arrayFrom(projectService.openFiles.keys(), path => projectService.getScriptInfoForPath(path as Path).fileName), expectedFiles.map(file => file.path));
|
||||
checkArray("Open files", arrayFrom(projectService.openFiles.keys(), path => projectService.getScriptInfoForPath(path as Path)!.fileName), expectedFiles.map(file => file.path));
|
||||
}
|
||||
|
||||
function textSpanFromSubstring(str: string, substring: string): TextSpan {
|
||||
@@ -420,7 +419,7 @@ namespace ts.projectSystem {
|
||||
* setRequestToCancel();
|
||||
*/
|
||||
export class TestServerCancellationToken implements server.ServerCancellationToken {
|
||||
private currentId = -1;
|
||||
private currentId: number | undefined = -1;
|
||||
private requestToCancel = -1;
|
||||
private isCancellationRequestedCount = 0;
|
||||
|
||||
@@ -708,7 +707,7 @@ namespace ts.projectSystem {
|
||||
projectService.checkNumberOfProjects({ inferredProjects: 2, configuredProjects: 1 });
|
||||
assert.isTrue(projectService.inferredProjects[0].isOrphan());
|
||||
checkProjectActualFiles(projectService.inferredProjects[1], [commonFile2.path, libFile.path]);
|
||||
checkProjectActualFiles(projectService.configuredProjects.get(configFile.path), [libFile.path, commonFile1.path, configFile.path]);
|
||||
checkProjectActualFiles(projectService.configuredProjects.get(configFile.path)!, [libFile.path, commonFile1.path, configFile.path]);
|
||||
|
||||
checkWatchedFiles(host, watchedFiles);
|
||||
|
||||
@@ -1106,15 +1105,15 @@ namespace ts.projectSystem {
|
||||
const projectService = createProjectService(host);
|
||||
|
||||
projectService.openExternalProject({ rootFiles: toExternalFiles([file1.path]), options: {}, projectFileName: proj1name });
|
||||
const proj1 = projectService.findProject(proj1name);
|
||||
const proj1 = projectService.findProject(proj1name)!;
|
||||
assert.isTrue(proj1.languageServiceEnabled);
|
||||
|
||||
projectService.openExternalProject({ rootFiles: toExternalFiles([file2.path]), options: {}, projectFileName: proj2name });
|
||||
const proj2 = projectService.findProject(proj2name);
|
||||
const proj2 = projectService.findProject(proj2name)!;
|
||||
assert.isTrue(proj2.languageServiceEnabled);
|
||||
|
||||
projectService.openExternalProject({ rootFiles: toExternalFiles([file3.path]), options: {}, projectFileName: proj3name });
|
||||
const proj3 = projectService.findProject(proj3name);
|
||||
const proj3 = projectService.findProject(proj3name)!;
|
||||
assert.isFalse(proj3.languageServiceEnabled);
|
||||
});
|
||||
|
||||
@@ -1182,7 +1181,7 @@ namespace ts.projectSystem {
|
||||
const projectService = createProjectService(host, { useSingleInferredProject: true });
|
||||
projectService.openClientFile(file1.path);
|
||||
checkNumberOfConfiguredProjects(projectService, 1);
|
||||
const project = projectService.configuredProjects.get(configFile.path);
|
||||
const project = projectService.configuredProjects.get(configFile.path)!;
|
||||
assert.isTrue(project.hasOpenRef()); // file1
|
||||
|
||||
projectService.closeClientFile(file1.path);
|
||||
@@ -1216,7 +1215,7 @@ namespace ts.projectSystem {
|
||||
const projectService = createProjectService(host, { useSingleInferredProject: true });
|
||||
projectService.openClientFile(file1.path);
|
||||
checkNumberOfConfiguredProjects(projectService, 1);
|
||||
const project = projectService.configuredProjects.get(configFile.path);
|
||||
const project = projectService.configuredProjects.get(configFile.path)!;
|
||||
assert.isTrue(project.hasOpenRef()); // file1
|
||||
|
||||
projectService.closeClientFile(file1.path);
|
||||
@@ -1489,13 +1488,13 @@ namespace ts.projectSystem {
|
||||
service.checkNumberOfProjects({ externalProjects: 1 });
|
||||
checkProjectActualFiles(service.externalProjects[0], [f1.path, f2.path, libFile.path]);
|
||||
|
||||
const completions1 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 2, defaultPreferences);
|
||||
const completions1 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 2, defaultPreferences)!;
|
||||
// should contain completions for string
|
||||
assert.isTrue(completions1.entries.some(e => e.name === "charAt"), "should contain 'charAt'");
|
||||
assert.isFalse(completions1.entries.some(e => e.name === "toExponential"), "should not contain 'toExponential'");
|
||||
|
||||
service.closeClientFile(f2.path);
|
||||
const completions2 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 2, defaultPreferences);
|
||||
const completions2 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 2, defaultPreferences)!;
|
||||
// should contain completions for string
|
||||
assert.isFalse(completions2.entries.some(e => e.name === "charAt"), "should not contain 'charAt'");
|
||||
assert.isTrue(completions2.entries.some(e => e.name === "toExponential"), "should contain 'toExponential'");
|
||||
@@ -1521,13 +1520,13 @@ namespace ts.projectSystem {
|
||||
service.checkNumberOfProjects({ externalProjects: 1 });
|
||||
checkProjectActualFiles(service.externalProjects[0], [f1.path, f2.path, libFile.path]);
|
||||
|
||||
const completions1 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 0, defaultPreferences);
|
||||
const completions1 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 0, defaultPreferences)!;
|
||||
assert.isTrue(completions1.entries.some(e => e.name === "somelongname"), "should contain 'somelongname'");
|
||||
|
||||
service.closeClientFile(f2.path);
|
||||
const completions2 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 0, defaultPreferences);
|
||||
const completions2 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 0, defaultPreferences)!;
|
||||
assert.isFalse(completions2.entries.some(e => e.name === "somelongname"), "should not contain 'somelongname'");
|
||||
const sf2 = service.externalProjects[0].getLanguageService().getProgram().getSourceFile(f2.path);
|
||||
const sf2 = service.externalProjects[0].getLanguageService().getProgram()!.getSourceFile(f2.path)!;
|
||||
assert.equal(sf2.text, "");
|
||||
});
|
||||
|
||||
@@ -2048,8 +2047,8 @@ namespace ts.projectSystem {
|
||||
const projectService = createProjectService(host);
|
||||
projectService.applyChangesInOpenFiles([tsFile], [], []);
|
||||
const projs = projectService.synchronizeProjectList([]);
|
||||
projectService.findProject(projs[0].info.projectName).getLanguageService().getNavigationBarItems(tsFile.fileName);
|
||||
projectService.synchronizeProjectList([projs[0].info]);
|
||||
projectService.findProject(projs[0].info!.projectName)!.getLanguageService().getNavigationBarItems(tsFile.fileName);
|
||||
projectService.synchronizeProjectList([projs[0].info!]);
|
||||
projectService.applyChangesInOpenFiles([jsFile], [], []);
|
||||
});
|
||||
|
||||
@@ -2333,7 +2332,7 @@ namespace ts.projectSystem {
|
||||
|
||||
const project = projectService.externalProjects[0];
|
||||
|
||||
const scriptInfo = project.getScriptInfo(file1.path);
|
||||
const scriptInfo = project.getScriptInfo(file1.path)!;
|
||||
const snap = scriptInfo.getSnapshot();
|
||||
const actualText = getSnapshotText(snap);
|
||||
assert.equal(actualText, "", `expected content to be empty string, got "${actualText}"`);
|
||||
@@ -2341,12 +2340,12 @@ namespace ts.projectSystem {
|
||||
projectService.openClientFile(file1.path, `var x = 1;`);
|
||||
project.updateGraph();
|
||||
|
||||
const quickInfo = project.getLanguageService().getQuickInfoAtPosition(file1.path, 4);
|
||||
const quickInfo = project.getLanguageService().getQuickInfoAtPosition(file1.path, 4)!;
|
||||
assert.equal(quickInfo.kind, ScriptElementKind.variableElement);
|
||||
|
||||
projectService.closeClientFile(file1.path);
|
||||
|
||||
const scriptInfo2 = project.getScriptInfo(file1.path);
|
||||
const scriptInfo2 = project.getScriptInfo(file1.path)!;
|
||||
const actualText2 = getSnapshotText(scriptInfo2.getSnapshot());
|
||||
assert.equal(actualText2, "", `expected content to be empty string, got "${actualText2}"`);
|
||||
});
|
||||
@@ -2391,7 +2390,7 @@ namespace ts.projectSystem {
|
||||
projectService.openClientFile(file1.path);
|
||||
projectService.inferredProjects[0].getLanguageService(/*ensureSynchronized*/ false).getOutliningSpans(file1.path);
|
||||
projectService.setCompilerOptionsForInferredProjects({ target: ScriptTarget.ES5, allowJs: true });
|
||||
projectService.getScriptInfo(file1.path).editContent(0, 0, " ");
|
||||
projectService.getScriptInfo(file1.path)!.editContent(0, 0, " ");
|
||||
projectService.inferredProjects[0].getLanguageService(/*ensureSynchronized*/ false).getOutliningSpans(file1.path);
|
||||
projectService.closeClientFile(file1.path);
|
||||
});
|
||||
@@ -2418,9 +2417,9 @@ namespace ts.projectSystem {
|
||||
|
||||
projectService.openClientFile(file2.path);
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
const project1 = projectService.configuredProjects.get(tsconfig1.path);
|
||||
const project1 = projectService.configuredProjects.get(tsconfig1.path)!;
|
||||
assert.isTrue(project1.hasOpenRef(), "Has open ref count in project1 - 1"); // file2
|
||||
assert.equal(project1.getScriptInfo(file2.path).containingProjects.length, 1, "containing projects count");
|
||||
assert.equal(project1.getScriptInfo(file2.path)!.containingProjects.length, 1, "containing projects count");
|
||||
assert.isFalse(project1.isClosed());
|
||||
|
||||
projectService.openClientFile(file1.path);
|
||||
@@ -2429,12 +2428,12 @@ namespace ts.projectSystem {
|
||||
assert.strictEqual(projectService.configuredProjects.get(tsconfig1.path), project1);
|
||||
assert.isFalse(project1.isClosed());
|
||||
|
||||
const project2 = projectService.configuredProjects.get(tsconfig2.path);
|
||||
const project2 = projectService.configuredProjects.get(tsconfig2.path)!;
|
||||
assert.isTrue(project2.hasOpenRef(), "Has open ref count in project2 - 2"); // file1
|
||||
assert.isFalse(project2.isClosed());
|
||||
|
||||
assert.equal(project1.getScriptInfo(file1.path).containingProjects.length, 2, `${file1.path} containing projects count`);
|
||||
assert.equal(project1.getScriptInfo(file2.path).containingProjects.length, 1, `${file2.path} containing projects count`);
|
||||
assert.equal(project1.getScriptInfo(file1.path)!.containingProjects.length, 2, `${file1.path} containing projects count`);
|
||||
assert.equal(project1.getScriptInfo(file2.path)!.containingProjects.length, 1, `${file2.path} containing projects count`);
|
||||
|
||||
projectService.closeClientFile(file2.path);
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 2 });
|
||||
@@ -2494,10 +2493,10 @@ namespace ts.projectSystem {
|
||||
projectService.openClientFile(file3.path);
|
||||
projectService.openClientFile(file4.path);
|
||||
|
||||
const infos = files.map(file => projectService.getScriptInfoForPath(file.path as Path));
|
||||
const infos = files.map(file => projectService.getScriptInfoForPath(file.path as Path)!);
|
||||
checkOpenFiles(projectService, files);
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 2 });
|
||||
const configProject1 = projectService.configuredProjects.get(configFile.path);
|
||||
const configProject1 = projectService.configuredProjects.get(configFile.path)!;
|
||||
assert.isTrue(configProject1.hasOpenRef()); // file1 and file3
|
||||
checkProjectActualFiles(configProject1, [file1.path, file3.path, configFile.path]);
|
||||
const inferredProject1 = projectService.inferredProjects[0];
|
||||
@@ -2568,7 +2567,7 @@ namespace ts.projectSystem {
|
||||
|
||||
function verifyConfiguredProjectStateAfterUpdate(hasOpenRef: boolean, inferredProjects: number) {
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects });
|
||||
const configProject2 = projectService.configuredProjects.get(configFile.path);
|
||||
const configProject2 = projectService.configuredProjects.get(configFile.path)!;
|
||||
assert.strictEqual(configProject2, configProject1);
|
||||
checkProjectActualFiles(configProject2, [file1.path, file2.path, file3.path, configFile.path]);
|
||||
assert.equal(configProject2.hasOpenRef(), hasOpenRef);
|
||||
@@ -2607,7 +2606,7 @@ namespace ts.projectSystem {
|
||||
projectService.openClientFile(file3.path);
|
||||
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 1 });
|
||||
const configuredProject = projectService.configuredProjects.get(configFile.path);
|
||||
const configuredProject = projectService.configuredProjects.get(configFile.path)!;
|
||||
assert.isTrue(configuredProject.hasOpenRef()); // file1 and file3
|
||||
checkProjectActualFiles(configuredProject, [file1.path, file3.path, configFile.path]);
|
||||
const inferredProject1 = projectService.inferredProjects[0];
|
||||
@@ -2709,7 +2708,7 @@ namespace ts.projectSystem {
|
||||
const projectService = createProjectService(host);
|
||||
projectService.openClientFile(f1.path);
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
const project = projectService.configuredProjects.get(config.path);
|
||||
const project = projectService.configuredProjects.get(config.path)!;
|
||||
assert.isTrue(project.hasOpenRef()); // f1
|
||||
assert.isFalse(project.isClosed());
|
||||
|
||||
@@ -2721,7 +2720,7 @@ namespace ts.projectSystem {
|
||||
|
||||
for (const f of [f1, f2, f3]) {
|
||||
// All the script infos should be present and contain the project since it is still alive.
|
||||
const scriptInfo = projectService.getScriptInfoForNormalizedPath(server.toNormalizedPath(f.path));
|
||||
const scriptInfo = projectService.getScriptInfoForNormalizedPath(server.toNormalizedPath(f.path))!;
|
||||
assert.equal(scriptInfo.containingProjects.length, 1, `expect 1 containing projects for '${f.path}'`);
|
||||
assert.equal(scriptInfo.containingProjects[0], project, `expect configured project to be the only containing project for '${f.path}'`);
|
||||
}
|
||||
@@ -2764,7 +2763,7 @@ namespace ts.projectSystem {
|
||||
host.getFileSize = (filePath: string) =>
|
||||
filePath === f2.path ? server.maxProgramSizeForNonTsFiles + 1 : originalGetFileSize.call(host, filePath);
|
||||
|
||||
let lastEvent: server.ProjectLanguageServiceStateEvent;
|
||||
let lastEvent!: server.ProjectLanguageServiceStateEvent;
|
||||
const session = createSession(host, {
|
||||
canUseEvents: true,
|
||||
eventHandler: e => {
|
||||
@@ -2816,7 +2815,7 @@ namespace ts.projectSystem {
|
||||
const originalGetFileSize = host.getFileSize;
|
||||
host.getFileSize = (filePath: string) =>
|
||||
filePath === f2.path ? server.maxProgramSizeForNonTsFiles + 1 : originalGetFileSize.call(host, filePath);
|
||||
let lastEvent: server.ProjectLanguageServiceStateEvent;
|
||||
let lastEvent!: server.ProjectLanguageServiceStateEvent;
|
||||
const session = createSession(host, {
|
||||
canUseEvents: true,
|
||||
eventHandler: e => {
|
||||
@@ -2906,7 +2905,7 @@ namespace ts.projectSystem {
|
||||
host.reloadFS([libFile, site]);
|
||||
host.checkTimeoutQueueLengthAndRun(1);
|
||||
|
||||
knownProjects = projectService.synchronizeProjectList(map(knownProjects, proj => proj.info));
|
||||
knownProjects = projectService.synchronizeProjectList(map(knownProjects, proj => proj.info!)); // TODO: GH#18217 GH#20039
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 0, externalProjects: 0, inferredProjects: 0 });
|
||||
|
||||
externalProject.rootFiles.length = 1;
|
||||
@@ -2979,7 +2978,7 @@ namespace ts.projectSystem {
|
||||
const projectService = createProjectService(host);
|
||||
projectService.openClientFile(file1.path);
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
const project = projectService.configuredProjects.get(configFile.path);
|
||||
const project = projectService.configuredProjects.get(configFile.path)!;
|
||||
assert.isDefined(project);
|
||||
checkProjectActualFiles(project, map(files, file => file.path));
|
||||
checkWatchedFiles(host, mapDefined(files, file => file === file1 ? undefined : file.path));
|
||||
@@ -3040,7 +3039,7 @@ namespace ts.projectSystem {
|
||||
const projectService = createProjectService(host);
|
||||
projectService.openClientFile(file1.path);
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
const project = projectService.configuredProjects.get(configFile.path);
|
||||
const project = projectService.configuredProjects.get(configFile.path)!;
|
||||
assert.isDefined(project);
|
||||
checkProjectActualFiles(project, [file1.path, libFile.path, module1.path, module2.path, configFile.path]);
|
||||
checkWatchedFiles(host, [libFile.path, module1.path, module2.path, configFile.path]);
|
||||
@@ -3145,7 +3144,7 @@ namespace ts.projectSystem {
|
||||
});
|
||||
|
||||
const projectService = session.getProjectService();
|
||||
const configuredProject = projectService.configuredProjects.get(config.path);
|
||||
const configuredProject = projectService.configuredProjects.get(config.path)!;
|
||||
verifyConfiguredProject();
|
||||
|
||||
// open files/file1 = should not create another project
|
||||
@@ -3296,7 +3295,7 @@ namespace ts.projectSystem {
|
||||
const host = createServerHost(files);
|
||||
const service = createProjectService(host);
|
||||
service.openClientFile(file1.path);
|
||||
checkProjectActualFiles(service.configuredProjects.get(config.path), [file1.path, file2.path, libFile.path, config.path]);
|
||||
checkProjectActualFiles(service.configuredProjects.get(config.path)!, [file1.path, file2.path, libFile.path, config.path]);
|
||||
|
||||
const configContent2 = JSON.stringify({
|
||||
files: ["src/file1.ts"]
|
||||
@@ -3305,19 +3304,18 @@ namespace ts.projectSystem {
|
||||
host.reloadFS(files);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
|
||||
checkProjectActualFiles(service.configuredProjects.get(config.path), [file1.path, libFile.path, config.path]);
|
||||
checkProjectActualFiles(service.configuredProjects.get(config.path)!, [file1.path, libFile.path, config.path]);
|
||||
verifyFile2InfoIsOrphan();
|
||||
|
||||
file2.content += "export let z = 10;";
|
||||
host.reloadFS(files);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
|
||||
checkProjectActualFiles(service.configuredProjects.get(config.path), [file1.path, libFile.path, config.path]);
|
||||
checkProjectActualFiles(service.configuredProjects.get(config.path)!, [file1.path, libFile.path, config.path]);
|
||||
verifyFile2InfoIsOrphan();
|
||||
|
||||
function verifyFile2InfoIsOrphan() {
|
||||
const info = service.getScriptInfoForPath(file2.path as Path);
|
||||
assert.isDefined(info);
|
||||
const info = Debug.assertDefined(service.getScriptInfoForPath(file2.path as Path));
|
||||
assert.equal(info.containingProjects.length, 0);
|
||||
}
|
||||
});
|
||||
@@ -3339,7 +3337,7 @@ namespace ts.projectSystem {
|
||||
},
|
||||
startGroup: noop,
|
||||
endGroup: noop,
|
||||
getLogFileName: (): string => undefined
|
||||
getLogFileName: () => undefined
|
||||
};
|
||||
return {
|
||||
errorLogger,
|
||||
@@ -3362,7 +3360,7 @@ namespace ts.projectSystem {
|
||||
projectService.openClientFile(file1.path);
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
|
||||
const project = projectService.findProject(corruptedConfig.path);
|
||||
const project = projectService.findProject(corruptedConfig.path)!;
|
||||
checkProjectRootFiles(project, [file1.path]);
|
||||
});
|
||||
|
||||
@@ -3904,7 +3902,7 @@ namespace ts.projectSystem {
|
||||
const projectService = createProjectService(host);
|
||||
projectService.openClientFile(f.path);
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
const project = projectService.configuredProjects.get(config.path);
|
||||
const project = projectService.configuredProjects.get(config.path)!;
|
||||
assert.isTrue(project.hasOpenRef()); // f
|
||||
|
||||
projectService.closeClientFile(f.path);
|
||||
@@ -4053,7 +4051,7 @@ namespace ts.projectSystem {
|
||||
// force to load the content of the file
|
||||
p.updateGraph();
|
||||
|
||||
const scriptInfo = p.getScriptInfo(f.path);
|
||||
const scriptInfo = p.getScriptInfo(f.path)!;
|
||||
checkSnapLength(scriptInfo.getSnapshot(), f.content.length);
|
||||
|
||||
// open project and replace its content with empty string
|
||||
@@ -4137,7 +4135,7 @@ namespace ts.projectSystem {
|
||||
|
||||
function verifyProject() {
|
||||
assert.isDefined(service.configuredProjects.get(configFile.path));
|
||||
const project = service.configuredProjects.get(configFile.path);
|
||||
const project = service.configuredProjects.get(configFile.path)!;
|
||||
checkProjectActualFiles(project, files.map(f => f.path));
|
||||
}
|
||||
});
|
||||
@@ -5037,7 +5035,7 @@ namespace ts.projectSystem {
|
||||
|
||||
// verify content
|
||||
const projectServiice = session.getProjectService();
|
||||
const snap1 = projectServiice.getScriptInfo(f1.path).getSnapshot();
|
||||
const snap1 = projectServiice.getScriptInfo(f1.path)!.getSnapshot();
|
||||
assert.equal(getSnapshotText(snap1), tmp.content, "content should be equal to the content of temp file");
|
||||
|
||||
// reload from original file file
|
||||
@@ -5049,7 +5047,7 @@ namespace ts.projectSystem {
|
||||
});
|
||||
|
||||
// verify content
|
||||
const snap2 = projectServiice.getScriptInfo(f1.path).getSnapshot();
|
||||
const snap2 = projectServiice.getScriptInfo(f1.path)!.getSnapshot();
|
||||
assert.equal(getSnapshotText(snap2), f1.content, "content should be equal to the content of original file");
|
||||
|
||||
});
|
||||
@@ -5074,7 +5072,7 @@ namespace ts.projectSystem {
|
||||
|
||||
const projectService = session.getProjectService();
|
||||
checkNumberOfProjects(projectService, { inferredProjects: 1 });
|
||||
const info = projectService.getScriptInfo(f1.path);
|
||||
const info = projectService.getScriptInfo(f1.path)!;
|
||||
assert.isDefined(info);
|
||||
checkScriptInfoContents(openContent, "contents set during open request");
|
||||
|
||||
@@ -5647,8 +5645,7 @@ namespace ts.projectSystem {
|
||||
|
||||
function verifyConfiguredProject(host: TestServerHost, projectService: TestProjectService, orphanInferredProject?: boolean) {
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1, inferredProjects: orphanInferredProject ? 1 : 0 });
|
||||
const project = projectService.configuredProjects.get(tsconfig.path);
|
||||
assert.isDefined(project);
|
||||
const project = Debug.assertDefined(projectService.configuredProjects.get(tsconfig.path));
|
||||
|
||||
if (orphanInferredProject) {
|
||||
const inferredProject = projectService.inferredProjects[0];
|
||||
@@ -6240,7 +6237,7 @@ namespace ts.projectSystem {
|
||||
const calledMap = createMultiMap<[U, V, W, X]>();
|
||||
const cb = (<any>host)[prop].bind(host);
|
||||
(<any>host)[prop] = (f: string, arg1?: U, arg2?: V, arg3?: W, arg4?: X) => {
|
||||
calledMap.add(f, [arg1, arg2, arg3, arg4]);
|
||||
calledMap.add(f, [arg1!, arg2!, arg3!, arg4!]); // TODO: GH#18217
|
||||
return cb(f, arg1, arg2, arg3, arg4);
|
||||
};
|
||||
return calledMap;
|
||||
@@ -6495,7 +6492,7 @@ namespace ts.projectSystem {
|
||||
assert.isDefined(configFileName, `should find config`);
|
||||
checkNumberOfConfiguredProjects(projectService, 1);
|
||||
|
||||
const project = projectService.configuredProjects.get(tsconfigFile.path);
|
||||
const project = projectService.configuredProjects.get(tsconfigFile.path)!;
|
||||
checkProjectActualFiles(project, map(projectFiles, f => f.path));
|
||||
|
||||
const callsTrackingHost = createCallsTrackingHost(host);
|
||||
@@ -6504,8 +6501,8 @@ namespace ts.projectSystem {
|
||||
const getDefinitionRequest = makeSessionRequest<protocol.FileLocationRequestArgs>(protocol.CommandTypes.Definition, {
|
||||
file: clientFile.path,
|
||||
position: clientFile.content.indexOf("/vessel") + 1,
|
||||
line: undefined,
|
||||
offset: undefined
|
||||
line: undefined!, // TODO: GH#18217
|
||||
offset: undefined! // TODO: GH#18217
|
||||
});
|
||||
const response = session.executeCommand(getDefinitionRequest).response as server.protocol.FileSpan[];
|
||||
assert.equal(response[0].file, moduleFile.path, "Should go to definition of vessel: response: " + JSON.stringify(response));
|
||||
@@ -6581,11 +6578,11 @@ namespace ts.projectSystem {
|
||||
const projectService = createProjectService(host);
|
||||
const canonicalConfigPath = toCanonical(tsconfigFile.path);
|
||||
const { configFileName } = projectService.openClientFile(file1.path);
|
||||
assert.equal(configFileName, tsconfigFile.path, `should find config`);
|
||||
assert.equal(configFileName, tsconfigFile.path as server.NormalizedPath, `should find config`); // tslint:disable-line no-unnecessary-type-assertion (TODO: GH#18217)
|
||||
checkNumberOfConfiguredProjects(projectService, 1);
|
||||
const watchingRecursiveDirectories = [`${canonicalFrontendDir}/src`, canonicalFrontendDir].concat(getNodeModuleDirectories(getDirectoryPath(canonicalFrontendDir)));
|
||||
|
||||
const project = projectService.configuredProjects.get(canonicalConfigPath);
|
||||
const project = projectService.configuredProjects.get(canonicalConfigPath)!;
|
||||
verifyProjectAndWatchedDirectories();
|
||||
|
||||
const callsTrackingHost = createCallsTrackingHost(host);
|
||||
@@ -6664,7 +6661,7 @@ namespace ts.projectSystem {
|
||||
const service = createProjectService(host);
|
||||
service.openClientFile(file1.path);
|
||||
|
||||
const project = service.configuredProjects.get(tsconfig.path);
|
||||
const project = service.configuredProjects.get(tsconfig.path)!;
|
||||
checkProjectActualFiles(project, files.map(f => f.path));
|
||||
assert.deepEqual(project.getLanguageService().getSemanticDiagnostics(file1.path).map(diag => diag.messageText), ["Cannot find module 'debug'."]);
|
||||
assert.deepEqual(project.getLanguageService().getSemanticDiagnostics(file2.path).map(diag => diag.messageText), ["Cannot find module 'debug'."]);
|
||||
@@ -6736,7 +6733,7 @@ namespace ts.projectSystem {
|
||||
const host = createServerHost(projectFiles.concat(otherFiles));
|
||||
const projectService = createProjectService(host);
|
||||
const { configFileName } = projectService.openClientFile(app.path);
|
||||
assert.equal(configFileName, tsconfigJson.path, `should find config`);
|
||||
assert.equal(configFileName, tsconfigJson.path as server.NormalizedPath, `should find config`); // TODO: GH#18217
|
||||
const recursiveWatchedDirectories: string[] = [appFolder].concat(getNodeModuleDirectories(getDirectoryPath(appFolder)));
|
||||
verifyProject();
|
||||
|
||||
@@ -6815,7 +6812,7 @@ namespace ts.projectSystem {
|
||||
});
|
||||
|
||||
const lodashIndexPath = root + "/a/b/node_modules/@types/lodash/index.d.ts";
|
||||
projectFiles.push(find(filesAndFoldersToAdd, f => f.path === lodashIndexPath));
|
||||
projectFiles.push(find(filesAndFoldersToAdd, f => f.path === lodashIndexPath)!);
|
||||
// we would now not have failed lookup in the parent of appFolder since lodash is available
|
||||
recursiveWatchedDirectories.length = 1;
|
||||
// npm installation complete, timeout after reload fs
|
||||
@@ -6836,7 +6833,7 @@ namespace ts.projectSystem {
|
||||
function verifyProject() {
|
||||
checkNumberOfConfiguredProjects(projectService, 1);
|
||||
|
||||
const project = projectService.configuredProjects.get(tsconfigJson.path);
|
||||
const project = projectService.configuredProjects.get(tsconfigJson.path)!;
|
||||
const projectFilePaths = map(projectFiles, f => f.path);
|
||||
checkProjectActualFiles(project, projectFilePaths);
|
||||
|
||||
@@ -6872,7 +6869,7 @@ namespace ts.projectSystem {
|
||||
const service = createProjectService(host);
|
||||
service.openClientFile(app.path);
|
||||
|
||||
const project = service.configuredProjects.get(tsconfig.path);
|
||||
const project = service.configuredProjects.get(tsconfig.path)!;
|
||||
checkProjectActualFiles(project, files.map(f => f.path));
|
||||
assert.deepEqual(project.getLanguageService().getSemanticDiagnostics(app.path).map(diag => diag.messageText), ["Cannot find module 'debug'."]);
|
||||
|
||||
@@ -7071,7 +7068,7 @@ namespace ts.projectSystem {
|
||||
content: JSON.stringify(configObj || { compilerOptions: {} })
|
||||
};
|
||||
|
||||
const files = [file1Consumer1, moduleFile1, file1Consumer2, moduleFile2, ...additionalFiles, globalFile3, libFile, configFile];
|
||||
const files: File[] = [file1Consumer1, moduleFile1, file1Consumer2, moduleFile2, ...additionalFiles, globalFile3, libFile, configFile];
|
||||
|
||||
const filesToReload = firstReloadFileList && getFiles(firstReloadFileList) || files;
|
||||
const host = createServerHost([filesToReload[0], configFile]);
|
||||
@@ -7097,7 +7094,7 @@ namespace ts.projectSystem {
|
||||
}
|
||||
|
||||
function getFile(fileName: string) {
|
||||
return find(files, file => file.path === fileName);
|
||||
return find(files, file => file.path === fileName)!;
|
||||
}
|
||||
|
||||
function verifyNoProjectsUpdatedInBackgroundEvent(filesToReload?: File[]) {
|
||||
@@ -7345,7 +7342,7 @@ namespace ts.projectSystem {
|
||||
const projectService = session.getProjectService();
|
||||
verifyInitialOpen(file1);
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
const project = projectService.configuredProjects.get(configFile.path);
|
||||
const project = projectService.configuredProjects.get(configFile.path)!;
|
||||
verifyProject();
|
||||
if (limitHit) {
|
||||
(project as ResolutionCacheHost).maxNumberOfFilesToIterateForInvalidation = 1;
|
||||
@@ -7521,7 +7518,7 @@ namespace ts.projectSystem {
|
||||
const host = createServerHost(files, { useWindowsStylePaths: true });
|
||||
const projectService = createProjectService(host);
|
||||
projectService.openClientFile(file1.path);
|
||||
const project = projectService.configuredProjects.get(configFile.path);
|
||||
const project = projectService.configuredProjects.get(configFile.path)!;
|
||||
assert.isDefined(project);
|
||||
const winsowsStyleLibFilePath = "c:/" + libFile.path.substring(1);
|
||||
checkProjectActualFiles(project, files.map(f => f === libFile ? winsowsStyleLibFilePath : f.path));
|
||||
@@ -7849,7 +7846,7 @@ new C();`
|
||||
|
||||
function verifyProjectWithResolvedModule(session: TestSession) {
|
||||
const projectService = session.getProjectService();
|
||||
const project = projectService.configuredProjects.get(recognizerDateTimeTsconfigPath);
|
||||
const project = projectService.configuredProjects.get(recognizerDateTimeTsconfigPath)!;
|
||||
checkProjectActualFiles(project, filesInProjectWithResolvedModule);
|
||||
verifyWatchedFilesAndDirectories(session.host, filesInProjectWithResolvedModule, watchedDirectoriesWithResolvedModule);
|
||||
verifyErrors(session, []);
|
||||
@@ -7857,7 +7854,7 @@ new C();`
|
||||
|
||||
function verifyProjectWithUnresolvedModule(session: TestSession) {
|
||||
const projectService = session.getProjectService();
|
||||
const project = projectService.configuredProjects.get(recognizerDateTimeTsconfigPath);
|
||||
const project = projectService.configuredProjects.get(recognizerDateTimeTsconfigPath)!;
|
||||
checkProjectActualFiles(project, filesInProjectWithUnresolvedModule);
|
||||
verifyWatchedFilesAndDirectories(session.host, filesInProjectWithUnresolvedModule, watchedDirectoriesWithUnresolvedModule);
|
||||
const startOffset = recognizersDateTimeSrcFile.content.indexOf('"') + 1;
|
||||
@@ -8358,8 +8355,7 @@ new C();`
|
||||
const projectService = createProjectService(host);
|
||||
projectService.openClientFile(index.path);
|
||||
|
||||
const project = projectService.configuredProjects.get(configFile.path);
|
||||
assert.isDefined(project);
|
||||
const project = Debug.assertDefined(projectService.configuredProjects.get(configFile.path));
|
||||
verifyProjectAndCompletions();
|
||||
|
||||
// Add file2
|
||||
@@ -8377,7 +8373,7 @@ new C();`
|
||||
verifyProjectAndCompletions();
|
||||
|
||||
function verifyProjectAndCompletions() {
|
||||
const completions = project.getLanguageService().getCompletionsAtPosition(index.path, completionPosition, { includeExternalModuleExports: false, includeInsertTextCompletions: false });
|
||||
const completions = project.getLanguageService().getCompletionsAtPosition(index.path, completionPosition, { includeExternalModuleExports: false, includeInsertTextCompletions: false })!;
|
||||
checkArray("Completion Entries", completions.entries.map(e => e.name), expectedCompletions);
|
||||
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ true);
|
||||
@@ -8443,7 +8439,7 @@ new C();`
|
||||
};
|
||||
|
||||
function getProject(service: TestProjectService) {
|
||||
return service.configuredProjects.get(configFile.path);
|
||||
return service.configuredProjects.get(configFile.path)!;
|
||||
}
|
||||
|
||||
function checkProject(service: TestProjectService, moduleIsOrphan: boolean) {
|
||||
@@ -8451,7 +8447,7 @@ new C();`
|
||||
const project = getProject(service);
|
||||
project.getLanguageService();
|
||||
checkProjectActualFiles(project, [file.path, libFile.path, configFile.path, ...(moduleIsOrphan ? [] : [moduleFile.path])]);
|
||||
const moduleInfo = service.getScriptInfo(moduleFile.path);
|
||||
const moduleInfo = service.getScriptInfo(moduleFile.path)!;
|
||||
assert.isDefined(moduleInfo);
|
||||
assert.equal(moduleInfo.isOrphan(), moduleIsOrphan);
|
||||
const key = service.documentRegistry.getKeyForCompilationSettings(project.getCompilationSettings());
|
||||
@@ -8467,13 +8463,13 @@ new C();`
|
||||
}
|
||||
|
||||
function changeFileToNotImportModule(service: TestProjectService) {
|
||||
const info = service.getScriptInfo(file.path);
|
||||
const info = service.getScriptInfo(file.path)!;
|
||||
service.applyChangesToFile(info, [{ span: { start: 0, length: importModuleContent.length }, newText: "" }]);
|
||||
checkProject(service, /*moduleIsOrphan*/ true);
|
||||
}
|
||||
|
||||
function changeFileToImportModule(service: TestProjectService) {
|
||||
const info = service.getScriptInfo(file.path);
|
||||
const info = service.getScriptInfo(file.path)!;
|
||||
service.applyChangesToFile(info, [{ span: { start: 0, length: 0 }, newText: importModuleContent }]);
|
||||
checkProject(service, /*moduleIsOrphan*/ false);
|
||||
}
|
||||
@@ -8482,7 +8478,7 @@ new C();`
|
||||
const { service } = createServiceAndHost();
|
||||
const project = getProject(service);
|
||||
|
||||
const moduleInfo = service.getScriptInfo(moduleFile.path);
|
||||
const moduleInfo = service.getScriptInfo(moduleFile.path)!;
|
||||
const sourceFile = moduleInfo.cacheSourceFile.sourceFile;
|
||||
assert.equal(project.getSourceFile(moduleInfo.path), sourceFile);
|
||||
|
||||
@@ -8500,7 +8496,7 @@ new C();`
|
||||
const { host, service } = createServiceAndHost();
|
||||
const project = getProject(service);
|
||||
|
||||
const moduleInfo = service.getScriptInfo(moduleFile.path);
|
||||
const moduleInfo = service.getScriptInfo(moduleFile.path)!;
|
||||
const sourceFile = moduleInfo.cacheSourceFile.sourceFile;
|
||||
assert.equal(project.getSourceFile(moduleInfo.path), sourceFile);
|
||||
|
||||
|
||||
@@ -1447,7 +1447,7 @@ namespace ts.projectSystem {
|
||||
commander: { typingLocation: commander.path, version: Semver.parse("1.3.0-next.0") }
|
||||
});
|
||||
const registry = createTypesRegistry("node", "commander");
|
||||
registry.get("node")[`ts${versionMajorMinor}`] = "1.3.0-next.1";
|
||||
registry.get("node")![`ts${versionMajorMinor}`] = "1.3.0-next.1";
|
||||
const logger = trackingLogger();
|
||||
const result = JsTyping.discoverTypings(host, logger.log, [app.path], getDirectoryPath(<Path>app.path), emptySafeList, cache, { enable: true }, ["http", "commander"], registry);
|
||||
assert.deepEqual(logger.finish(), [
|
||||
@@ -1535,8 +1535,8 @@ namespace ts.projectSystem {
|
||||
content: "export let x: number"
|
||||
};
|
||||
const host = createServerHost([f1, packageFile, packageLockFile]);
|
||||
let beginEvent: server.BeginInstallTypes;
|
||||
let endEvent: server.EndInstallTypes;
|
||||
let beginEvent!: server.BeginInstallTypes;
|
||||
let endEvent!: server.EndInstallTypes;
|
||||
const installer = new (class extends Installer {
|
||||
constructor() {
|
||||
super(host, { globalTypingsCacheLocation: cachePath, typesRegistry: createTypesRegistry("commander") });
|
||||
@@ -1583,8 +1583,8 @@ namespace ts.projectSystem {
|
||||
};
|
||||
const cachePath = "/a/cache/";
|
||||
const host = createServerHost([f1, packageFile]);
|
||||
let beginEvent: server.BeginInstallTypes;
|
||||
let endEvent: server.EndInstallTypes;
|
||||
let beginEvent: server.BeginInstallTypes | undefined;
|
||||
let endEvent: server.EndInstallTypes | undefined;
|
||||
const installer: Installer = new (class extends Installer {
|
||||
constructor() {
|
||||
super(host, { globalTypingsCacheLocation: cachePath, typesRegistry: createTypesRegistry("commander") });
|
||||
@@ -1611,8 +1611,8 @@ namespace ts.projectSystem {
|
||||
|
||||
assert.isTrue(!!beginEvent);
|
||||
assert.isTrue(!!endEvent);
|
||||
assert.isTrue(beginEvent.eventId === endEvent.eventId);
|
||||
assert.isFalse(endEvent.installSuccess);
|
||||
assert.isTrue(beginEvent!.eventId === endEvent!.eventId);
|
||||
assert.isFalse(endEvent!.installSuccess);
|
||||
checkNumberOfProjects(projectService, { inferredProjects: 1 });
|
||||
checkProjectActualFiles(projectService.inferredProjects[0], [f1.path]);
|
||||
});
|
||||
@@ -1651,7 +1651,7 @@ namespace ts.projectSystem {
|
||||
const appPath = "/a/b/app.js" as Path;
|
||||
const foooPath = "/a/b/node_modules/fooo/index.d.ts";
|
||||
function verifyResolvedModuleOfFooo(project: server.Project) {
|
||||
const foooResolution = project.getLanguageService().getProgram().getSourceFileByPath(appPath).resolvedModules.get("fooo");
|
||||
const foooResolution = project.getLanguageService().getProgram()!.getSourceFileByPath(appPath)!.resolvedModules!.get("fooo")!;
|
||||
assert.equal(foooResolution.resolvedFileName, foooPath);
|
||||
return foooResolution;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ var q:Point=<Point>p;`;
|
||||
});
|
||||
|
||||
after(() => {
|
||||
validateEditAtLineCharIndex = undefined;
|
||||
validateEditAtLineCharIndex = undefined!;
|
||||
});
|
||||
|
||||
it("handles empty lines array", () => {
|
||||
@@ -105,10 +105,10 @@ and grew 1cm per day`;
|
||||
});
|
||||
|
||||
after(() => {
|
||||
validateEditAtPosition = undefined;
|
||||
testContent = undefined;
|
||||
lines = undefined;
|
||||
lineMap = undefined;
|
||||
validateEditAtPosition = undefined!;
|
||||
testContent = undefined!;
|
||||
lines = undefined!;
|
||||
lineMap = undefined!;
|
||||
});
|
||||
|
||||
it(`Insert at end of file`, () => {
|
||||
@@ -201,7 +201,7 @@ and grew 1cm per day`;
|
||||
before(() => {
|
||||
// Use scanner.ts, decent size, does not change frequently
|
||||
const testFileName = "src/compiler/scanner.ts";
|
||||
testContent = Harness.IO.readFile(testFileName);
|
||||
testContent = Harness.IO.readFile(testFileName)!;
|
||||
const totalChars = testContent.length;
|
||||
assert.isTrue(totalChars > 0, "Failed to read test file.");
|
||||
|
||||
@@ -237,16 +237,16 @@ and grew 1cm per day`;
|
||||
});
|
||||
|
||||
after(() => {
|
||||
rsa = undefined;
|
||||
la = undefined;
|
||||
las = undefined;
|
||||
elas = undefined;
|
||||
ersa = undefined;
|
||||
ela = undefined;
|
||||
lines = undefined;
|
||||
lineMap = undefined;
|
||||
lineIndex = undefined;
|
||||
testContent = undefined;
|
||||
rsa = undefined!;
|
||||
la = undefined!;
|
||||
las = undefined!;
|
||||
elas = undefined!;
|
||||
ersa = undefined!;
|
||||
ela = undefined!;
|
||||
lines = undefined!;
|
||||
lineMap = undefined!;
|
||||
lineIndex = undefined!;
|
||||
testContent = undefined!;
|
||||
});
|
||||
|
||||
it("Range (average length 1/4 file size)", () => {
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*/
|
||||
namespace utils {
|
||||
const testPathPrefixRegExp = /(?:(file:\/{3})|\/)\.(ts|lib|src)\//g;
|
||||
export function removeTestPathPrefixes(text: string, retainTrailingDirectorySeparator?: boolean) {
|
||||
return text !== undefined ? text.replace(testPathPrefixRegExp, (_, scheme) => scheme || (retainTrailingDirectorySeparator ? "/" : "")) : undefined;
|
||||
export function removeTestPathPrefixes(text: string, retainTrailingDirectorySeparator?: boolean): string {
|
||||
return text !== undefined ? text.replace(testPathPrefixRegExp, (_, scheme) => scheme || (retainTrailingDirectorySeparator ? "/" : "")) : undefined!; // TODO: GH#18217
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,7 +49,7 @@ namespace utils {
|
||||
}
|
||||
|
||||
function guessIndentation(lines: string[]) {
|
||||
let indentation: number;
|
||||
let indentation: number | undefined;
|
||||
for (const line of lines) {
|
||||
for (let i = 0; i < line.length && (indentation === undefined || i < indentation); i++) {
|
||||
if (!ts.isWhiteSpaceLike(line.charCodeAt(i))) {
|
||||
|
||||
+5
-5
@@ -935,7 +935,7 @@ namespace vfs {
|
||||
this._applyFilesWorker(value.files, path, deferred);
|
||||
}
|
||||
else {
|
||||
deferred.push([value as Symlink | Link | Mount, path]);
|
||||
deferred.push([value, path]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -998,7 +998,7 @@ namespace vfs {
|
||||
directoryExists(path: string): boolean;
|
||||
fileExists(path: string): boolean;
|
||||
getFileSize(path: string): number;
|
||||
readFile(path: string): string;
|
||||
readFile(path: string): string | undefined;
|
||||
getWorkspaceRoot(): string;
|
||||
}
|
||||
|
||||
@@ -1020,7 +1020,7 @@ namespace vfs {
|
||||
}
|
||||
},
|
||||
readFileSync(path: string): Buffer {
|
||||
return Buffer.from(host.readFile(path), "utf8");
|
||||
return Buffer.from(host.readFile(path)!, "utf8"); // TODO: GH#18217
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1241,7 +1241,7 @@ namespace vfs {
|
||||
ctimeMs: number; // status change time
|
||||
birthtimeMs: number; // creation time
|
||||
nlink: number; // number of hard links
|
||||
symlink?: string;
|
||||
symlink: string;
|
||||
shadowRoot?: SymlinkInode;
|
||||
meta?: collections.Metadata;
|
||||
}
|
||||
@@ -1262,7 +1262,7 @@ namespace vfs {
|
||||
realpath: string;
|
||||
basename: string;
|
||||
parent: DirectoryInode | undefined;
|
||||
links: collections.SortedMap<string, Inode> | undefined;
|
||||
links: collections.SortedMap<string, Inode>;
|
||||
node: Inode | undefined;
|
||||
}
|
||||
|
||||
|
||||
@@ -179,7 +179,7 @@ interface Array<T> {}`
|
||||
verifyMapSize(caption, actual, arrayFrom(expectedKeys.keys()));
|
||||
expectedKeys.forEach((count, name) => {
|
||||
assert.isTrue(actual.has(name), `${caption}: expected to contain ${name}, actual keys: ${arrayFrom(actual.keys())}`);
|
||||
assert.equal(actual.get(name).length, count, `${caption}: Expected to be have ${count} entries for ${name}. Actual entry: ${JSON.stringify(actual.get(name))}`);
|
||||
assert.equal(actual.get(name)!.length, count, `${caption}: Expected to be have ${count} entries for ${name}. Actual entry: ${JSON.stringify(actual.get(name))}`);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -322,7 +322,7 @@ interface Array<T> {}`
|
||||
readonly watchedFiles = createMultiMap<TestFileWatcher>();
|
||||
private readonly executingFilePath: string;
|
||||
private readonly currentDirectory: string;
|
||||
private readonly dynamicPriorityWatchFile: HostWatchFile;
|
||||
private readonly dynamicPriorityWatchFile: HostWatchFile | undefined;
|
||||
private readonly customRecursiveWatchDirectory: HostWatchDirectory | undefined;
|
||||
|
||||
constructor(public withSafeList: boolean, public useCaseSensitiveFileNames: boolean, executingFilePath: string, currentDirectory: string, fileOrFolderorSymLinkList: ReadonlyArray<FileOrFolderOrSymLink>, public readonly newLine = "\n", public readonly useWindowsStylePath?: boolean, private readonly environmentVariables?: Map<string>) {
|
||||
@@ -465,7 +465,7 @@ interface Array<T> {}`
|
||||
else {
|
||||
currentEntry.content = content;
|
||||
currentEntry.modifiedTime = this.now();
|
||||
this.fs.get(getDirectoryPath(currentEntry.path)).modifiedTime = this.now();
|
||||
this.fs.get(getDirectoryPath(currentEntry.path))!.modifiedTime = this.now();
|
||||
if (options && options.invokeDirectoryWatcherInsteadOfFileChanged) {
|
||||
this.invokeDirectoryWatcher(getDirectoryPath(currentEntry.fullPath), currentEntry.fullPath);
|
||||
}
|
||||
@@ -570,7 +570,7 @@ interface Array<T> {}`
|
||||
this.invokeDirectoryWatcher(folder.fullPath, fileOrDirectory.fullPath);
|
||||
}
|
||||
|
||||
private removeFileOrFolder(fileOrDirectory: FsFile | FsFolder | FsSymLink, isRemovableLeafFolder: (folder: FsFolder) => boolean, isRenaming?: boolean) {
|
||||
private removeFileOrFolder(fileOrDirectory: FsFile | FsFolder | FsSymLink, isRemovableLeafFolder: (folder: FsFolder) => boolean, isRenaming = false) {
|
||||
const basePath = getDirectoryPath(fileOrDirectory.path);
|
||||
const baseFolder = this.fs.get(basePath) as FsFolder;
|
||||
if (basePath !== fileOrDirectory.path) {
|
||||
@@ -621,15 +621,15 @@ interface Array<T> {}`
|
||||
|
||||
// For overriding the methods
|
||||
invokeWatchedDirectoriesCallback(folderFullPath: string, relativePath: string) {
|
||||
invokeWatcherCallbacks(this.watchedDirectories.get(this.toPath(folderFullPath)), cb => this.directoryCallback(cb, relativePath));
|
||||
invokeWatcherCallbacks(this.watchedDirectories.get(this.toPath(folderFullPath))!, cb => this.directoryCallback(cb, relativePath));
|
||||
}
|
||||
|
||||
invokeWatchedDirectoriesRecursiveCallback(folderFullPath: string, relativePath: string) {
|
||||
invokeWatcherCallbacks(this.watchedDirectoriesRecursive.get(this.toPath(folderFullPath)), cb => this.directoryCallback(cb, relativePath));
|
||||
invokeWatcherCallbacks(this.watchedDirectoriesRecursive.get(this.toPath(folderFullPath))!, cb => this.directoryCallback(cb, relativePath));
|
||||
}
|
||||
|
||||
invokeFileWatcher(fileFullPath: string, eventKind: FileWatcherEventKind, useFileNameInCallback?: boolean) {
|
||||
invokeWatcherCallbacks(this.watchedFiles.get(this.toPath(fileFullPath)), ({ cb, fileName }) => cb(useFileNameInCallback ? fileName : fileFullPath, eventKind));
|
||||
invokeWatcherCallbacks(this.watchedFiles.get(this.toPath(fileFullPath))!, ({ cb, fileName }) => cb(useFileNameInCallback ? fileName : fileFullPath, eventKind));
|
||||
}
|
||||
|
||||
private getRelativePathToDirectory(directoryFullPath: string, fileFullPath: string) {
|
||||
@@ -687,11 +687,11 @@ interface Array<T> {}`
|
||||
|
||||
private toFsFolder(path: string): FsFolder {
|
||||
const fsFolder = this.toFsEntry(path) as FsFolder;
|
||||
fsFolder.entries = [] as SortedArray<FSEntry>;
|
||||
fsFolder.entries = [] as FSEntry[] as SortedArray<FSEntry>; // https://github.com/Microsoft/TypeScript/issues/19873
|
||||
return fsFolder;
|
||||
}
|
||||
|
||||
private getRealFsEntry<T extends FSEntry>(isFsEntry: (fsEntry: FSEntry) => fsEntry is T, path: Path, fsEntry = this.fs.get(path)): T | undefined {
|
||||
private getRealFsEntry<T extends FSEntry>(isFsEntry: (fsEntry: FSEntry) => fsEntry is T, path: Path, fsEntry = this.fs.get(path)!): T | undefined {
|
||||
if (isFsEntry(fsEntry)) {
|
||||
return fsEntry;
|
||||
}
|
||||
@@ -737,21 +737,21 @@ interface Array<T> {}`
|
||||
getModifiedTime(s: string) {
|
||||
const path = this.toFullPath(s);
|
||||
const fsEntry = this.fs.get(path);
|
||||
return fsEntry && fsEntry.modifiedTime;
|
||||
return (fsEntry && fsEntry.modifiedTime)!; // TODO: GH#18217
|
||||
}
|
||||
|
||||
readFile(s: string): string {
|
||||
readFile(s: string): string | undefined {
|
||||
const fsEntry = this.getRealFile(this.toFullPath(s));
|
||||
return fsEntry ? fsEntry.content : undefined;
|
||||
}
|
||||
|
||||
getFileSize(s: string) {
|
||||
const path = this.toFullPath(s);
|
||||
const entry = this.fs.get(path);
|
||||
const entry = this.fs.get(path)!;
|
||||
if (isFsFile(entry)) {
|
||||
return entry.fileSize ? entry.fileSize : entry.content.length;
|
||||
}
|
||||
return undefined;
|
||||
return undefined!; // TODO: GH#18217
|
||||
}
|
||||
|
||||
directoryExists(s: string) {
|
||||
@@ -812,7 +812,7 @@ interface Array<T> {}`
|
||||
}
|
||||
|
||||
createSHA256Hash(s: string): string {
|
||||
return sys.createSHA256Hash(s);
|
||||
return sys.createSHA256Hash!(s);
|
||||
}
|
||||
|
||||
watchFile(fileName: string, cb: FileWatcherCallback, pollingInterval: number) {
|
||||
@@ -925,7 +925,7 @@ interface Array<T> {}`
|
||||
}
|
||||
const dirFullPath = this.realpath(getDirectoryPath(fullPath));
|
||||
const realFullPath = combinePaths(dirFullPath, getBaseFileName(fullPath));
|
||||
const fsEntry = this.fs.get(this.toPath(realFullPath));
|
||||
const fsEntry = this.fs.get(this.toPath(realFullPath))!;
|
||||
if (isFsSymLink(fsEntry)) {
|
||||
return this.realpath(fsEntry.symLink);
|
||||
}
|
||||
@@ -934,7 +934,7 @@ interface Array<T> {}`
|
||||
}
|
||||
|
||||
readonly exitMessage = "System Exit";
|
||||
exitCode: number;
|
||||
exitCode: number | undefined;
|
||||
readonly resolvePath = (s: string) => s;
|
||||
readonly getExecutingFilePath = () => this.executingFilePath;
|
||||
readonly getCurrentDirectory = () => this.currentDirectory;
|
||||
@@ -943,7 +943,7 @@ interface Array<T> {}`
|
||||
throw new Error(this.exitMessage);
|
||||
}
|
||||
getEnvironmentVariable(name: string) {
|
||||
return this.environmentVariables && this.environmentVariables.get(name);
|
||||
return this.environmentVariables && this.environmentVariables.get(name) || "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user