mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-24 20:44:53 -05:00
Detangle unittests to reference helpers directly (#51450)
* Remove unnecessary redirection now that we are not in namespaces * Move the tsc helpers in one place * Move virtual file system with watch in unittests folder instead of harness since harness doesnt use it anyways * Replace protocol and commandNames * Revert incorrect pick
This commit is contained in:
@@ -1,3 +0,0 @@
|
||||
/* Generated file to emulate the ts.TestFSWithWatch namespace. */
|
||||
|
||||
export * from "../virtualFileSystemWithWatch";
|
||||
@@ -8,6 +8,4 @@ export * from "../../typingsInstallerCore/_namespaces/ts";
|
||||
export * from "../../deprecatedCompat/_namespaces/ts";
|
||||
export * from "../harnessGlobals";
|
||||
import * as server from "./ts.server";
|
||||
export { server };
|
||||
import * as TestFSWithWatch from "./ts.TestFSWithWatch";
|
||||
export { TestFSWithWatch };
|
||||
export { server };
|
||||
@@ -42,6 +42,8 @@ export interface DiffOptions {
|
||||
baseIsNotShadowRoot?: boolean;
|
||||
}
|
||||
|
||||
export const timeIncrements = 1000;
|
||||
|
||||
/**
|
||||
* Represents a virtual POSIX-like file system.
|
||||
*/
|
||||
@@ -65,7 +67,7 @@ export class FileSystem {
|
||||
private _dirStack: string[] | undefined;
|
||||
|
||||
constructor(ignoreCase: boolean, options: FileSystemOptions = {}) {
|
||||
const { time = ts.TestFSWithWatch.timeIncrements, files, meta } = options;
|
||||
const { time = timeIncrements, files, meta } = options;
|
||||
this.ignoreCase = ignoreCase;
|
||||
this.stringComparer = this.ignoreCase ? vpath.compareCaseInsensitive : vpath.compareCaseSensitive;
|
||||
this._time = time;
|
||||
@@ -178,7 +180,7 @@ export class FileSystem {
|
||||
this._time = value;
|
||||
}
|
||||
else if (!this.isReadonly) {
|
||||
this._time += ts.TestFSWithWatch.timeIncrements;
|
||||
this._time += timeIncrements;
|
||||
}
|
||||
return this._time;
|
||||
}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
/* Generated file to emulate the ts.projectSystem namespace. */
|
||||
|
||||
export * from "../unittests/tsserver/helpers";
|
||||
@@ -10,13 +10,5 @@ export * from "../../typingsInstallerCore/_namespaces/ts";
|
||||
export * from "../../deprecatedCompat/_namespaces/ts";
|
||||
export * from "../../harness/_namespaces/ts";
|
||||
export * from "../../loggedIO/_namespaces/ts";
|
||||
import * as tscWatch from "./ts.tscWatch";
|
||||
export { tscWatch };
|
||||
import * as server from "./ts.server";
|
||||
export { server };
|
||||
import * as projectSystem from "./ts.projectSystem";
|
||||
export { projectSystem };
|
||||
export * from "../unittests/helpers";
|
||||
export * from "../unittests/services/extract/helpers";
|
||||
export * from "../unittests/tsbuild/helpers";
|
||||
export * from "../unittests/tsc/helpers";
|
||||
export { server };
|
||||
@@ -1,3 +0,0 @@
|
||||
/* Generated file to emulate the ts.tscWatch namespace. */
|
||||
|
||||
export * from "../unittests/tscWatch/helpers";
|
||||
@@ -1,14 +1,15 @@
|
||||
import * as ts from "../_namespaces/ts";
|
||||
import { NamedSourceText, newProgram, ProgramWithSourceTexts, SourceText, updateProgram, updateProgramText } from "./helpers";
|
||||
|
||||
describe("unittests:: builder", () => {
|
||||
it("emits dependent files", () => {
|
||||
const files: ts.NamedSourceText[] = [
|
||||
{ name: "/a.ts", text: ts.SourceText.New("", 'import { b } from "./b";', "") },
|
||||
{ name: "/b.ts", text: ts.SourceText.New("", ' import { c } from "./c";', "export const b = c;") },
|
||||
{ name: "/c.ts", text: ts.SourceText.New("", "", "export const c = 0;") },
|
||||
const files: NamedSourceText[] = [
|
||||
{ name: "/a.ts", text: SourceText.New("", 'import { b } from "./b";', "") },
|
||||
{ name: "/b.ts", text: SourceText.New("", ' import { c } from "./c";', "export const b = c;") },
|
||||
{ name: "/c.ts", text: SourceText.New("", "", "export const c = 0;") },
|
||||
];
|
||||
|
||||
let program = ts.newProgram(files, ["/a.ts"], {});
|
||||
let program = newProgram(files, ["/a.ts"], {});
|
||||
const assertChanges = makeAssertChanges(() => program);
|
||||
|
||||
assertChanges(["/c.js", "/b.js", "/a.js"]);
|
||||
@@ -24,12 +25,12 @@ describe("unittests:: builder", () => {
|
||||
});
|
||||
|
||||
it("if emitting all files, emits the changed file first", () => {
|
||||
const files: ts.NamedSourceText[] = [
|
||||
{ name: "/a.ts", text: ts.SourceText.New("", "", "namespace A { export const x = 0; }") },
|
||||
{ name: "/b.ts", text: ts.SourceText.New("", "", "namespace B { export const x = 0; }") },
|
||||
const files: NamedSourceText[] = [
|
||||
{ name: "/a.ts", text: SourceText.New("", "", "namespace A { export const x = 0; }") },
|
||||
{ name: "/b.ts", text: SourceText.New("", "", "namespace B { export const x = 0; }") },
|
||||
];
|
||||
|
||||
let program = ts.newProgram(files, ["/a.ts", "/b.ts"], {});
|
||||
let program = newProgram(files, ["/a.ts", "/b.ts"], {});
|
||||
const assertChanges = makeAssertChanges(() => program);
|
||||
|
||||
assertChanges(["/a.js", "/b.js"]);
|
||||
@@ -42,15 +43,15 @@ describe("unittests:: builder", () => {
|
||||
});
|
||||
|
||||
it("keeps the file in affected files if cancellation token throws during the operation", () => {
|
||||
const files: ts.NamedSourceText[] = [
|
||||
{ name: "/a.ts", text: ts.SourceText.New("", 'import { b } from "./b";', "") },
|
||||
{ name: "/b.ts", text: ts.SourceText.New("", ' import { c } from "./c";', "export const b = c;") },
|
||||
{ name: "/c.ts", text: ts.SourceText.New("", "", "export const c = 0;") },
|
||||
{ name: "/d.ts", text: ts.SourceText.New("", "", "export const dd = 0;") },
|
||||
{ name: "/e.ts", text: ts.SourceText.New("", "", "export const ee = 0;") },
|
||||
const files: NamedSourceText[] = [
|
||||
{ name: "/a.ts", text: SourceText.New("", 'import { b } from "./b";', "") },
|
||||
{ name: "/b.ts", text: SourceText.New("", ' import { c } from "./c";', "export const b = c;") },
|
||||
{ name: "/c.ts", text: SourceText.New("", "", "export const c = 0;") },
|
||||
{ name: "/d.ts", text: SourceText.New("", "", "export const dd = 0;") },
|
||||
{ name: "/e.ts", text: SourceText.New("", "", "export const ee = 0;") },
|
||||
];
|
||||
|
||||
let program = ts.newProgram(files, ["/d.ts", "/e.ts", "/a.ts"], {});
|
||||
let program = newProgram(files, ["/d.ts", "/e.ts", "/a.ts"], {});
|
||||
const assertChanges = makeAssertChangesWithCancellationToken(() => program);
|
||||
// No cancellation
|
||||
assertChanges(["/d.js", "/e.js", "/c.js", "/b.js", "/a.js"]);
|
||||
@@ -123,8 +124,8 @@ function makeAssertChangesWithCancellationToken(getProgram: () => ts.Program): (
|
||||
};
|
||||
}
|
||||
|
||||
function updateProgramFile(program: ts.ProgramWithSourceTexts, fileName: string, fileContent: string): ts.ProgramWithSourceTexts {
|
||||
return ts.updateProgram(program, program.getRootFileNames(), program.getCompilerOptions(), files => {
|
||||
ts.updateProgramText(files, fileName, fileContent);
|
||||
function updateProgramFile(program: ProgramWithSourceTexts, fileName: string, fileContent: string): ProgramWithSourceTexts {
|
||||
return updateProgram(program, program.getRootFileNames(), program.getCompilerOptions(), files => {
|
||||
updateProgramText(files, fileName, fileContent);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as fakes from "../../_namespaces/fakes";
|
||||
import * as vfs from "../../_namespaces/vfs";
|
||||
import { libFile } from "../virtualFileSystemWithWatch";
|
||||
|
||||
interface TestProjectSpecification {
|
||||
configFileName?: string;
|
||||
@@ -77,7 +78,7 @@ function testProjectReferences(spec: TestSpecification, entryPointConfigFileName
|
||||
}
|
||||
}
|
||||
|
||||
const vfsys = new vfs.FileSystem(false, { files: { "/lib.d.ts": ts.TestFSWithWatch.libFile.content } });
|
||||
const vfsys = new vfs.FileSystem(false, { files: { "/lib.d.ts": libFile.content } });
|
||||
files.forEach((v, k) => {
|
||||
vfsys.mkdirpSync(ts.getDirectoryPath(k));
|
||||
vfsys.writeFileSync(k, v);
|
||||
|
||||
@@ -204,7 +204,7 @@ function mapEqualToCache<T>(left: ts.ESMap<string, T>, right: ts.ModeAwareCache<
|
||||
}
|
||||
|
||||
export function checkResolvedModulesCache(program: ts.Program, fileName: string, expectedContent: ts.ESMap<string, ts.ResolvedModule | undefined> | undefined): void {
|
||||
checkCache("resolved modules", program, fileName, expectedContent, f => f.resolvedModules, ts.checkResolvedModule);
|
||||
checkCache("resolved modules", program, fileName, expectedContent, f => f.resolvedModules, checkResolvedModule);
|
||||
}
|
||||
|
||||
export function checkResolvedTypeDirectivesCache(program: ts.Program, fileName: string, expectedContent: ts.ESMap<string, ts.ResolvedTypeReferenceDirective> | undefined): void {
|
||||
|
||||
@@ -8,6 +8,42 @@ interface File {
|
||||
symlinks?: string[];
|
||||
}
|
||||
|
||||
function getDiagnosticMessageChain(message: ts.DiagnosticMessage, args?: (string | number)[], next?: ts.DiagnosticMessageChain[]): ts.DiagnosticMessageChain {
|
||||
let text = ts.getLocaleSpecificMessage(message);
|
||||
if (args?.length) {
|
||||
text = ts.formatStringFromArgs(text, args);
|
||||
}
|
||||
return {
|
||||
messageText: text,
|
||||
category: message.category,
|
||||
code: message.code,
|
||||
next
|
||||
};
|
||||
}
|
||||
|
||||
function isDiagnosticMessageChain(message: ts.DiagnosticMessage | ts.DiagnosticMessageChain): message is ts.DiagnosticMessageChain {
|
||||
return !!(message as ts.DiagnosticMessageChain).messageText;
|
||||
}
|
||||
|
||||
function getDiagnosticOfFileFrom(file: ts.SourceFile | undefined, start: number | undefined, length: number | undefined, message: ts.DiagnosticMessage | ts.DiagnosticMessageChain, ...args: (string | number)[]): ts.Diagnostic {
|
||||
return {
|
||||
file,
|
||||
start,
|
||||
length,
|
||||
|
||||
messageText: isDiagnosticMessageChain(message) ?
|
||||
message :
|
||||
getDiagnosticMessageChain(message, args).messageText,
|
||||
category: message.category,
|
||||
code: message.code,
|
||||
};
|
||||
}
|
||||
|
||||
function getDiagnosticOfFileFromProgram(program: ts.Program, filePath: string, start: number, length: number, message: ts.DiagnosticMessage | ts.DiagnosticMessageChain, ...args: (string | number)[]): ts.Diagnostic {
|
||||
return getDiagnosticOfFileFrom(program.getSourceFileByPath(ts.toPath(filePath, program.getCurrentDirectory(), s => s.toLowerCase())),
|
||||
start, length, message, ...args);
|
||||
}
|
||||
|
||||
function createModuleResolutionHost(hasDirectoryExists: boolean, ...files: File[]): ts.ModuleResolutionHost {
|
||||
const map = new ts.Map<string, File>();
|
||||
for (const file of files) {
|
||||
@@ -596,21 +632,21 @@ describe("unittests:: moduleResolution:: Files with different casing with forceC
|
||||
/*useCaseSensitiveFileNames*/ false,
|
||||
["c.ts", "d.ts"],
|
||||
program => [{
|
||||
...ts.tscWatch.getDiagnosticOfFileFromProgram(
|
||||
...getDiagnosticOfFileFromProgram(
|
||||
program,
|
||||
"c.ts",
|
||||
`/// <reference path="D.ts"/>`.indexOf(`D.ts`),
|
||||
"D.ts".length,
|
||||
ts.tscWatch.getDiagnosticMessageChain(
|
||||
getDiagnosticMessageChain(
|
||||
ts.Diagnostics.Already_included_file_name_0_differs_from_file_name_1_only_in_casing,
|
||||
["D.ts", "d.ts"],
|
||||
[
|
||||
ts.tscWatch.getDiagnosticMessageChain(
|
||||
getDiagnosticMessageChain(
|
||||
ts.Diagnostics.The_file_is_in_the_program_because_Colon,
|
||||
ts.emptyArray,
|
||||
[
|
||||
ts.tscWatch.getDiagnosticMessageChain(ts.Diagnostics.Referenced_via_0_from_file_1, ["D.ts", "c.ts"]),
|
||||
ts.tscWatch.getDiagnosticMessageChain(ts.Diagnostics.Root_file_specified_for_compilation)
|
||||
getDiagnosticMessageChain(ts.Diagnostics.Referenced_via_0_from_file_1, ["D.ts", "c.ts"]),
|
||||
getDiagnosticMessageChain(ts.Diagnostics.Root_file_specified_for_compilation)
|
||||
]
|
||||
)
|
||||
],
|
||||
@@ -633,21 +669,21 @@ describe("unittests:: moduleResolution:: Files with different casing with forceC
|
||||
/*useCaseSensitiveFileNames*/ false,
|
||||
["c.ts", "d.ts"],
|
||||
program => [{
|
||||
...ts.tscWatch.getDiagnosticOfFileFromProgram(
|
||||
...getDiagnosticOfFileFromProgram(
|
||||
program,
|
||||
"c.ts",
|
||||
`import {x} from "D"`.indexOf(`"D"`),
|
||||
`"D"`.length,
|
||||
ts.tscWatch.getDiagnosticMessageChain(
|
||||
getDiagnosticMessageChain(
|
||||
ts.Diagnostics.Already_included_file_name_0_differs_from_file_name_1_only_in_casing,
|
||||
["/a/b/D.ts", "d.ts"],
|
||||
[
|
||||
ts.tscWatch.getDiagnosticMessageChain(
|
||||
getDiagnosticMessageChain(
|
||||
ts.Diagnostics.The_file_is_in_the_program_because_Colon,
|
||||
ts.emptyArray,
|
||||
[
|
||||
ts.tscWatch.getDiagnosticMessageChain(ts.Diagnostics.Imported_via_0_from_file_1, [`"D"`, "c.ts"]),
|
||||
ts.tscWatch.getDiagnosticMessageChain(ts.Diagnostics.Root_file_specified_for_compilation)
|
||||
getDiagnosticMessageChain(ts.Diagnostics.Imported_via_0_from_file_1, [`"D"`, "c.ts"]),
|
||||
getDiagnosticMessageChain(ts.Diagnostics.Root_file_specified_for_compilation)
|
||||
]
|
||||
)
|
||||
],
|
||||
@@ -670,21 +706,21 @@ describe("unittests:: moduleResolution:: Files with different casing with forceC
|
||||
/*useCaseSensitiveFileNames*/ false,
|
||||
["moduleA.ts", "moduleB.ts"],
|
||||
program => [{
|
||||
...ts.tscWatch.getDiagnosticOfFileFromProgram(
|
||||
...getDiagnosticOfFileFromProgram(
|
||||
program,
|
||||
"moduleA.ts",
|
||||
`import {x} from "./ModuleB"`.indexOf(`"./ModuleB"`),
|
||||
`"./ModuleB"`.length,
|
||||
ts.tscWatch.getDiagnosticMessageChain(
|
||||
getDiagnosticMessageChain(
|
||||
ts.Diagnostics.Already_included_file_name_0_differs_from_file_name_1_only_in_casing,
|
||||
["ModuleB.ts", "moduleB.ts"],
|
||||
[
|
||||
ts.tscWatch.getDiagnosticMessageChain(
|
||||
getDiagnosticMessageChain(
|
||||
ts.Diagnostics.The_file_is_in_the_program_because_Colon,
|
||||
ts.emptyArray,
|
||||
[
|
||||
ts.tscWatch.getDiagnosticMessageChain(ts.Diagnostics.Imported_via_0_from_file_1, [`"./ModuleB"`, "moduleA.ts"]),
|
||||
ts.tscWatch.getDiagnosticMessageChain(ts.Diagnostics.Root_file_specified_for_compilation)
|
||||
getDiagnosticMessageChain(ts.Diagnostics.Imported_via_0_from_file_1, [`"./ModuleB"`, "moduleA.ts"]),
|
||||
getDiagnosticMessageChain(ts.Diagnostics.Root_file_specified_for_compilation)
|
||||
]
|
||||
)
|
||||
],
|
||||
@@ -708,21 +744,21 @@ describe("unittests:: moduleResolution:: Files with different casing with forceC
|
||||
/*useCaseSensitiveFileNames*/ true,
|
||||
["c.ts", "d.ts"],
|
||||
program => [{
|
||||
...ts.tscWatch.getDiagnosticOfFileFromProgram(
|
||||
...getDiagnosticOfFileFromProgram(
|
||||
program,
|
||||
"c.ts",
|
||||
`import {x} from "D"`.indexOf(`"D"`),
|
||||
`"D"`.length,
|
||||
ts.tscWatch.getDiagnosticMessageChain(
|
||||
getDiagnosticMessageChain(
|
||||
ts.Diagnostics.Already_included_file_name_0_differs_from_file_name_1_only_in_casing,
|
||||
["/a/b/D.ts", "d.ts"],
|
||||
[
|
||||
ts.tscWatch.getDiagnosticMessageChain(
|
||||
getDiagnosticMessageChain(
|
||||
ts.Diagnostics.The_file_is_in_the_program_because_Colon,
|
||||
ts.emptyArray,
|
||||
[
|
||||
ts.tscWatch.getDiagnosticMessageChain(ts.Diagnostics.Imported_via_0_from_file_1, [`"D"`, "c.ts"]),
|
||||
ts.tscWatch.getDiagnosticMessageChain(ts.Diagnostics.Root_file_specified_for_compilation)
|
||||
getDiagnosticMessageChain(ts.Diagnostics.Imported_via_0_from_file_1, [`"D"`, "c.ts"]),
|
||||
getDiagnosticMessageChain(ts.Diagnostics.Root_file_specified_for_compilation)
|
||||
]
|
||||
)
|
||||
],
|
||||
@@ -747,7 +783,7 @@ describe("unittests:: moduleResolution:: Files with different casing with forceC
|
||||
["moduleA.ts", "moduleB.ts", "moduleC.ts"],
|
||||
program => {
|
||||
const importInA = {
|
||||
...ts.tscWatch.getDiagnosticOfFileFromProgram(
|
||||
...getDiagnosticOfFileFromProgram(
|
||||
program,
|
||||
"moduleA.ts",
|
||||
`import a = require("./ModuleC")`.indexOf(`"./ModuleC"`),
|
||||
@@ -758,7 +794,7 @@ describe("unittests:: moduleResolution:: Files with different casing with forceC
|
||||
reportsDeprecated: undefined
|
||||
};
|
||||
const importInB = {
|
||||
...ts.tscWatch.getDiagnosticOfFileFromProgram(
|
||||
...getDiagnosticOfFileFromProgram(
|
||||
program,
|
||||
"moduleB.ts",
|
||||
`import a = require("./moduleC")`.indexOf(`"./moduleC"`),
|
||||
@@ -768,20 +804,20 @@ describe("unittests:: moduleResolution:: Files with different casing with forceC
|
||||
reportsUnnecessary: undefined,
|
||||
reportsDeprecated: undefined
|
||||
};
|
||||
const importHereInA = ts.tscWatch.getDiagnosticMessageChain(ts.Diagnostics.Imported_via_0_from_file_1, [`"./ModuleC"`, "moduleA.ts"]);
|
||||
const importHereInB = ts.tscWatch.getDiagnosticMessageChain(ts.Diagnostics.Imported_via_0_from_file_1, [`"./moduleC"`, "moduleB.ts"]);
|
||||
const details = [ts.tscWatch.getDiagnosticMessageChain(
|
||||
const importHereInA = getDiagnosticMessageChain(ts.Diagnostics.Imported_via_0_from_file_1, [`"./ModuleC"`, "moduleA.ts"]);
|
||||
const importHereInB = getDiagnosticMessageChain(ts.Diagnostics.Imported_via_0_from_file_1, [`"./moduleC"`, "moduleB.ts"]);
|
||||
const details = [getDiagnosticMessageChain(
|
||||
ts.Diagnostics.The_file_is_in_the_program_because_Colon,
|
||||
ts.emptyArray,
|
||||
[importHereInA, importHereInB, ts.tscWatch.getDiagnosticMessageChain(ts.Diagnostics.Root_file_specified_for_compilation)]
|
||||
[importHereInA, importHereInB, getDiagnosticMessageChain(ts.Diagnostics.Root_file_specified_for_compilation)]
|
||||
)];
|
||||
return [
|
||||
{
|
||||
...ts.tscWatch.getDiagnosticOfFileFrom(
|
||||
...getDiagnosticOfFileFrom(
|
||||
importInA.file,
|
||||
importInA.start,
|
||||
importInA.length,
|
||||
ts.tscWatch.getDiagnosticMessageChain(
|
||||
getDiagnosticMessageChain(
|
||||
ts.Diagnostics.Already_included_file_name_0_differs_from_file_name_1_only_in_casing,
|
||||
["ModuleC.ts", "moduleC.ts" ],
|
||||
details,
|
||||
@@ -790,11 +826,11 @@ describe("unittests:: moduleResolution:: Files with different casing with forceC
|
||||
relatedInformation: [importInB]
|
||||
},
|
||||
{
|
||||
...ts.tscWatch.getDiagnosticOfFileFrom(
|
||||
...getDiagnosticOfFileFrom(
|
||||
importInB.file,
|
||||
importInB.start,
|
||||
importInB.length,
|
||||
ts.tscWatch.getDiagnosticMessageChain(
|
||||
getDiagnosticMessageChain(
|
||||
ts.Diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing,
|
||||
["moduleC.ts", "ModuleC.ts"],
|
||||
details,
|
||||
@@ -824,21 +860,21 @@ import b = require("./moduleB");
|
||||
/*useCaseSensitiveFileNames*/ false,
|
||||
["moduleD.ts"],
|
||||
program => [{
|
||||
...ts.tscWatch.getDiagnosticOfFileFromProgram(
|
||||
...getDiagnosticOfFileFromProgram(
|
||||
program,
|
||||
"moduleB.ts",
|
||||
`import a = require("./moduleC")`.indexOf(`"./moduleC"`),
|
||||
`"./moduleC"`.length,
|
||||
ts.tscWatch.getDiagnosticMessageChain(
|
||||
getDiagnosticMessageChain(
|
||||
ts.Diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing,
|
||||
["/a/B/c/moduleC.ts", "/a/B/c/ModuleC.ts"],
|
||||
[
|
||||
ts.tscWatch.getDiagnosticMessageChain(
|
||||
getDiagnosticMessageChain(
|
||||
ts.Diagnostics.The_file_is_in_the_program_because_Colon,
|
||||
ts.emptyArray,
|
||||
[
|
||||
ts.tscWatch.getDiagnosticMessageChain(ts.Diagnostics.Imported_via_0_from_file_1, [`"./ModuleC"`, "/a/B/c/moduleA.ts"]),
|
||||
ts.tscWatch.getDiagnosticMessageChain(ts.Diagnostics.Imported_via_0_from_file_1, [`"./moduleC"`, "/a/B/c/moduleB.ts"])
|
||||
getDiagnosticMessageChain(ts.Diagnostics.Imported_via_0_from_file_1, [`"./ModuleC"`, "/a/B/c/moduleA.ts"]),
|
||||
getDiagnosticMessageChain(ts.Diagnostics.Imported_via_0_from_file_1, [`"./moduleC"`, "/a/B/c/moduleB.ts"])
|
||||
]
|
||||
)
|
||||
],
|
||||
@@ -846,7 +882,7 @@ import b = require("./moduleB");
|
||||
),
|
||||
relatedInformation: [
|
||||
{
|
||||
...ts.tscWatch.getDiagnosticOfFileFromProgram(
|
||||
...getDiagnosticOfFileFromProgram(
|
||||
program,
|
||||
"moduleA.ts",
|
||||
`import a = require("./ModuleC")`.indexOf(`"./ModuleC"`),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as ts from "../_namespaces/ts";
|
||||
|
||||
import { checkResolvedModulesCache, checkResolvedTypeDirectivesCache, createTestCompilerHost, NamedSourceText, newLine, newProgram, ProgramWithSourceTexts, SourceText, TestCompilerHost, updateProgram, updateProgramText } from "./helpers";
|
||||
import { checkResolvedModulesCache, checkResolvedTypeDirectivesCache, createResolvedModule, createTestCompilerHost, NamedSourceText, newLine, newProgram, ProgramWithSourceTexts, SourceText, TestCompilerHost, updateProgram, updateProgramText } from "./helpers";
|
||||
import { createWatchedSystem, File, libFile } from "./virtualFileSystemWithWatch";
|
||||
|
||||
describe("unittests:: Reuse program structure:: General", () => {
|
||||
const target = ts.ScriptTarget.Latest;
|
||||
@@ -155,7 +156,7 @@ describe("unittests:: Reuse program structure:: General", () => {
|
||||
const options: ts.CompilerOptions = { target };
|
||||
|
||||
const program1 = newProgram(files, ["a.ts"], options);
|
||||
checkResolvedModulesCache(program1, "a.ts", new ts.Map(ts.getEntries({ b: ts.createResolvedModule("b.ts") })));
|
||||
checkResolvedModulesCache(program1, "a.ts", new ts.Map(ts.getEntries({ b: createResolvedModule("b.ts") })));
|
||||
checkResolvedModulesCache(program1, "b.ts", /*expectedContent*/ undefined);
|
||||
|
||||
const program2 = updateProgram(program1, ["a.ts"], options, files => {
|
||||
@@ -164,7 +165,7 @@ describe("unittests:: Reuse program structure:: General", () => {
|
||||
assert.equal(program2.structureIsReused, ts.StructureIsReused.Completely);
|
||||
|
||||
// content of resolution cache should not change
|
||||
checkResolvedModulesCache(program1, "a.ts", new ts.Map(ts.getEntries({ b: ts.createResolvedModule("b.ts") })));
|
||||
checkResolvedModulesCache(program1, "a.ts", new ts.Map(ts.getEntries({ b: createResolvedModule("b.ts") })));
|
||||
checkResolvedModulesCache(program1, "b.ts", /*expectedContent*/ undefined);
|
||||
|
||||
// imports has changed - program is not reused
|
||||
@@ -181,7 +182,7 @@ describe("unittests:: Reuse program structure:: General", () => {
|
||||
files[0].text = files[0].text.updateImportsAndExports(newImports);
|
||||
});
|
||||
assert.equal(program4.structureIsReused, ts.StructureIsReused.SafeModules);
|
||||
checkResolvedModulesCache(program4, "a.ts", new ts.Map(ts.getEntries({ b: ts.createResolvedModule("b.ts"), c: undefined })));
|
||||
checkResolvedModulesCache(program4, "a.ts", new ts.Map(ts.getEntries({ b: createResolvedModule("b.ts"), c: undefined })));
|
||||
});
|
||||
|
||||
it("set the resolvedImports after re-using an ambient external module declaration", () => {
|
||||
@@ -692,9 +693,6 @@ describe("unittests:: Reuse program structure:: host is optional", () => {
|
||||
});
|
||||
});
|
||||
|
||||
type File = ts.TestFSWithWatch.File;
|
||||
import createTestSystem = ts.TestFSWithWatch.createWatchedSystem;
|
||||
import libFile = ts.TestFSWithWatch.libFile;
|
||||
|
||||
describe("unittests:: Reuse program structure:: isProgramUptoDate", () => {
|
||||
function getWhetherProgramIsUptoDate(
|
||||
@@ -748,7 +746,7 @@ describe("unittests:: Reuse program structure:: isProgramUptoDate", () => {
|
||||
}
|
||||
|
||||
function verifyProgram(files: File[], rootFiles: string[], options: ts.CompilerOptions, configFile: string) {
|
||||
const system = createTestSystem(files);
|
||||
const system = createWatchedSystem(files);
|
||||
verifyProgramWithoutConfigFile(system, rootFiles, options);
|
||||
verifyProgramWithConfigFile(system, configFile);
|
||||
}
|
||||
@@ -863,7 +861,7 @@ describe("unittests:: Reuse program structure:: isProgramUptoDate", () => {
|
||||
path: "/src/tsconfig.json",
|
||||
content: JSON.stringify({ compilerOptions, include: ["packages/**/*.ts"] })
|
||||
};
|
||||
verifyProgramWithConfigFile(createTestSystem([app, module1, module2, module3, libFile, configFile]), configFile.path);
|
||||
verifyProgramWithConfigFile(createWatchedSystem([app, module1, module2, module3, libFile, configFile]), configFile.path);
|
||||
});
|
||||
it("has the same root file names", () => {
|
||||
const module1: File = {
|
||||
@@ -879,7 +877,7 @@ describe("unittests:: Reuse program structure:: isProgramUptoDate", () => {
|
||||
content: "class classD { method() { return 10; } }\nexport default classD;"
|
||||
};
|
||||
const rootFiles = [module1.path, module2.path, module3.path];
|
||||
const system = createTestSystem([module1, module2, module3]);
|
||||
const system = createWatchedSystem([module1, module2, module3]);
|
||||
const options = {};
|
||||
const program = ts.createWatchProgram(ts.createWatchCompilerHostOfFilesAndCompilerOptions({
|
||||
rootFiles,
|
||||
@@ -915,7 +913,7 @@ describe("unittests:: Reuse program structure:: isProgramUptoDate", () => {
|
||||
};
|
||||
const rootFiles = [module1.path, module2.path];
|
||||
const newRootFiles = [module1.path, module2.path, module3.path];
|
||||
const system = createTestSystem([module1, module2, module3]);
|
||||
const system = createWatchedSystem([module1, module2, module3]);
|
||||
const options = {};
|
||||
const program = ts.createWatchProgram(ts.createWatchCompilerHostOfFilesAndCompilerOptions({
|
||||
rootFiles,
|
||||
@@ -940,7 +938,7 @@ describe("unittests:: Reuse program structure:: isProgramUptoDate", () => {
|
||||
};
|
||||
const rootFiles = [module1.path, module2.path];
|
||||
const newRootFiles = [module2.path, module3.path];
|
||||
const system = createTestSystem([module1, module2, module3]);
|
||||
const system = createWatchedSystem([module1, module2, module3]);
|
||||
const options = {};
|
||||
const program = ts.createWatchProgram(ts.createWatchCompilerHostOfFilesAndCompilerOptions({
|
||||
rootFiles,
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as Harness from "../../_namespaces/Harness";
|
||||
import { createServerHost, File } from "../virtualFileSystemWithWatch";
|
||||
import { createProjectService } from "../tsserver/helpers";
|
||||
import { extractTest, newLineCharacter, notImplementedHost } from "./extract/helpers";
|
||||
|
||||
const libFile: ts.TestFSWithWatch.File = {
|
||||
const libFile: File = {
|
||||
path: "/a/lib/lib.d.ts",
|
||||
content: `/// <reference no-default-lib="true"/>
|
||||
interface Boolean {}
|
||||
@@ -264,7 +267,7 @@ interface String { charAt: any; }
|
||||
interface Array<T> {}`
|
||||
};
|
||||
|
||||
const moduleFile: ts.TestFSWithWatch.File = {
|
||||
const moduleFile: File = {
|
||||
path: "/module.ts",
|
||||
content:
|
||||
`export function fn(res: any): any {
|
||||
@@ -310,7 +313,7 @@ function testConvertToAsyncFunction(it: Mocha.PendingTestFunction, caption: stri
|
||||
ts.Debug.assert(!(expectSuggestionDiagnostic && expectNoSuggestionDiagnostic), "Cannot combine both 'ExpectSuggestionDiagnostic' and 'ExpectNoSuggestionDiagnostic'");
|
||||
ts.Debug.assert(!(expectAction && expectNoAction), "Cannot combine both 'ExpectAction' and 'ExpectNoAction'");
|
||||
|
||||
const t = ts.extractTest(text);
|
||||
const t = extractTest(text);
|
||||
const selectionRange = t.ranges.get("selection")!;
|
||||
if (!selectionRange) {
|
||||
throw new Error(`Test ${caption} does not specify selection range`);
|
||||
@@ -345,8 +348,8 @@ function testConvertToAsyncFunction(it: Mocha.PendingTestFunction, caption: stri
|
||||
program,
|
||||
cancellationToken: { throwIfCancellationRequested: ts.noop, isCancellationRequested: ts.returnFalse },
|
||||
preferences: ts.emptyOptions,
|
||||
host: ts.notImplementedHost,
|
||||
formatContext: ts.formatting.getFormatContext(ts.testFormatSettings, ts.notImplementedHost)
|
||||
host: notImplementedHost,
|
||||
formatContext: ts.formatting.getFormatContext(ts.testFormatSettings, notImplementedHost)
|
||||
};
|
||||
|
||||
const diagnostics = languageService.getSuggestionDiagnostics(f.path);
|
||||
@@ -369,7 +372,7 @@ function testConvertToAsyncFunction(it: Mocha.PendingTestFunction, caption: stri
|
||||
|
||||
const diagProgram = makeLanguageService({ path, content: newText }, includeLib, includeModule).getProgram()!;
|
||||
assert.isFalse(hasSyntacticDiagnostics(diagProgram));
|
||||
outputText = data.join(ts.newLineCharacter);
|
||||
outputText = data.join(newLineCharacter);
|
||||
}
|
||||
else {
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
@@ -395,7 +398,7 @@ function testConvertToAsyncFunction(it: Mocha.PendingTestFunction, caption: stri
|
||||
}
|
||||
}
|
||||
|
||||
function makeLanguageService(file: ts.TestFSWithWatch.File, includeLib?: boolean, includeModule?: boolean) {
|
||||
function makeLanguageService(file: File, includeLib?: boolean, includeModule?: boolean) {
|
||||
const files = [file];
|
||||
if (includeLib) {
|
||||
files.push(libFile); // libFile is expensive to parse repeatedly - only test when required
|
||||
@@ -403,8 +406,8 @@ function testConvertToAsyncFunction(it: Mocha.PendingTestFunction, caption: stri
|
||||
if (includeModule) {
|
||||
files.push(moduleFile);
|
||||
}
|
||||
const host = ts.projectSystem.createServerHost(files);
|
||||
const projectService = ts.projectSystem.createProjectService(host);
|
||||
const host = createServerHost(files);
|
||||
const projectService = createProjectService(host);
|
||||
projectService.openClientFile(file.path);
|
||||
return ts.first(projectService.inferredProjects).getLanguageService();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as ts from "../../../_namespaces/ts";
|
||||
import { testExtractSymbol, testExtractSymbolFailed } from "./helpers";
|
||||
|
||||
describe("unittests:: services:: extract:: extractConstants", () => {
|
||||
testExtractConstant("extractConstant_TopLevel",
|
||||
@@ -296,9 +297,9 @@ switch (1) {
|
||||
});
|
||||
|
||||
function testExtractConstant(caption: string, text: string) {
|
||||
ts.testExtractSymbol(caption, text, "extractConstant", ts.Diagnostics.Extract_constant);
|
||||
testExtractSymbol(caption, text, "extractConstant", ts.Diagnostics.Extract_constant);
|
||||
}
|
||||
|
||||
function testExtractConstantFailed(caption: string, text: string) {
|
||||
ts.testExtractSymbolFailed(caption, text, ts.Diagnostics.Extract_constant);
|
||||
testExtractSymbolFailed(caption, text, ts.Diagnostics.Extract_constant);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as ts from "../../../_namespaces/ts";
|
||||
import { testExtractSymbol } from "./helpers";
|
||||
|
||||
describe("unittests:: services:: extract:: extractFunctions", () => {
|
||||
testExtractFunction("extractFunction1",
|
||||
@@ -565,5 +566,5 @@ function F() {
|
||||
});
|
||||
|
||||
function testExtractFunction(caption: string, text: string, includeLib?: boolean) {
|
||||
ts.testExtractSymbol(caption, text, "extractFunction", ts.Diagnostics.Extract_function, includeLib);
|
||||
testExtractSymbol(caption, text, "extractFunction", ts.Diagnostics.Extract_function, includeLib);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import * as ts from "../../../_namespaces/ts";
|
||||
import * as Harness from "../../../_namespaces/Harness";
|
||||
import { createServerHost, libFile } from "../../virtualFileSystemWithWatch";
|
||||
import { createProjectService } from "../../tsserver/helpers";
|
||||
|
||||
interface Range {
|
||||
pos: number;
|
||||
@@ -132,8 +134,8 @@ export function testExtractSymbol(caption: string, text: string, baselineFolder:
|
||||
}
|
||||
|
||||
function makeProgram(f: {path: string, content: string }, includeLib?: boolean) {
|
||||
const host = ts.projectSystem.createServerHost(includeLib ? [f, ts.projectSystem.libFile] : [f]); // libFile is expensive to parse repeatedly - only test when required
|
||||
const projectService = ts.projectSystem.createProjectService(host);
|
||||
const host = createServerHost(includeLib ? [f, libFile] : [f]); // libFile is expensive to parse repeatedly - only test when required
|
||||
const projectService = createProjectService(host);
|
||||
projectService.openClientFile(f.path);
|
||||
const program = projectService.inferredProjects[0].getLanguageService().getProgram()!;
|
||||
const autoImportProvider = projectService.inferredProjects[0].getLanguageService().getAutoImportProvider();
|
||||
@@ -157,8 +159,8 @@ export function testExtractSymbolFailed(caption: string, text: string, descripti
|
||||
path: "/a.ts",
|
||||
content: t.source
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([f, ts.projectSystem.libFile]);
|
||||
const projectService = ts.projectSystem.createProjectService(host);
|
||||
const host = createServerHost([f, libFile]);
|
||||
const projectService = createProjectService(host);
|
||||
projectService.openClientFile(f.path);
|
||||
const program = projectService.inferredProjects[0].getLanguageService().getProgram()!;
|
||||
const sourceFile = program.getSourceFile(f.path)!;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import * as ts from "../../../_namespaces/ts";
|
||||
import { extractTest } from "./helpers";
|
||||
|
||||
function testExtractRangeFailed(caption: string, s: string, expectedErrors: string[]) {
|
||||
return it(caption, () => {
|
||||
const t = ts.extractTest(s);
|
||||
const t = extractTest(s);
|
||||
const file = ts.createSourceFile("a.ts", t.source, ts.ScriptTarget.Latest, /*setParentNodes*/ true);
|
||||
const selectionRange = t.ranges.get("selection");
|
||||
if (!selectionRange) {
|
||||
@@ -17,7 +18,7 @@ function testExtractRangeFailed(caption: string, s: string, expectedErrors: stri
|
||||
|
||||
function testExtractRange(caption: string, s: string) {
|
||||
return it(caption, () => {
|
||||
const t = ts.extractTest(s);
|
||||
const t = extractTest(s);
|
||||
const f = ts.createSourceFile("a.ts", t.source, ts.ScriptTarget.Latest, /*setParentNodes*/ true);
|
||||
const selectionRange = t.ranges.get("selection");
|
||||
if (!selectionRange) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { createServerHost, File, libFile } from "../virtualFileSystemWithWatch";
|
||||
|
||||
describe("unittests:: services:: languageService", () => {
|
||||
const files: {[index: string]: string} = {
|
||||
@@ -90,7 +91,7 @@ export function Component(x: Config): any;`
|
||||
const files = new ts.Map<string, { version: string, text: string; }>();
|
||||
files.set("/project/root.ts", { version: "1", text: `import { foo } from "./other"` });
|
||||
files.set("/project/other.ts", { version: "1", text: `export function foo() { }` });
|
||||
files.set("/lib/lib.d.ts", { version: "1", text: ts.projectSystem.libFile.content });
|
||||
files.set("/lib/lib.d.ts", { version: "1", text: libFile.content });
|
||||
const host: ts.LanguageServiceHost = {
|
||||
useCaseSensitiveFileNames: ts.returnTrue,
|
||||
getCompilationSettings: ts.getDefaultCompilerOptions,
|
||||
@@ -143,8 +144,8 @@ export function Component(x: Config): any;`
|
||||
|
||||
describe("detects program upto date when new file is added to the referenced project", () => {
|
||||
function setup(useSourceOfProjectReferenceRedirect: (() => boolean) | undefined) {
|
||||
const config1: ts.TestFSWithWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/projects/project1/tsconfig.json`,
|
||||
const config1: File = {
|
||||
path: `/user/username/projects/myproject/projects/project1/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
module: "none",
|
||||
@@ -153,16 +154,16 @@ export function Component(x: Config): any;`
|
||||
exclude: ["temp"]
|
||||
})
|
||||
};
|
||||
const class1: ts.TestFSWithWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/projects/project1/class1.ts`,
|
||||
const class1: File = {
|
||||
path: `/user/username/projects/myproject/projects/project1/class1.ts`,
|
||||
content: `class class1 {}`
|
||||
};
|
||||
const class1Dts: ts.TestFSWithWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/projects/project1/class1.d.ts`,
|
||||
const class1Dts: File = {
|
||||
path: `/user/username/projects/myproject/projects/project1/class1.d.ts`,
|
||||
content: `declare class class1 {}`
|
||||
};
|
||||
const config2: ts.TestFSWithWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/projects/project2/tsconfig.json`,
|
||||
const config2: File = {
|
||||
path: `/user/username/projects/myproject/projects/project2/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
module: "none",
|
||||
@@ -173,12 +174,12 @@ export function Component(x: Config): any;`
|
||||
]
|
||||
})
|
||||
};
|
||||
const class2: ts.TestFSWithWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/projects/project2/class2.ts`,
|
||||
const class2: File = {
|
||||
path: `/user/username/projects/myproject/projects/project2/class2.ts`,
|
||||
content: `class class2 {}`
|
||||
};
|
||||
const system = ts.projectSystem.createServerHost([config1, class1, class1Dts, config2, class2, ts.projectSystem.libFile]);
|
||||
const result = ts.getParsedCommandLineOfConfigFile(`${ts.tscWatch.projectRoot}/projects/project2/tsconfig.json`, /*optionsToExtend*/ undefined, {
|
||||
const system = createServerHost([config1, class1, class1Dts, config2, class2, libFile]);
|
||||
const result = ts.getParsedCommandLineOfConfigFile(`/user/username/projects/myproject/projects/project2/tsconfig.json`, /*optionsToExtend*/ undefined, {
|
||||
useCaseSensitiveFileNames: true,
|
||||
fileExists: path => system.fileExists(path),
|
||||
readFile: path => system.readFile(path),
|
||||
@@ -203,7 +204,7 @@ export function Component(x: Config): any;`
|
||||
},
|
||||
readDirectory: (path, extensions, excludes, includes, depth) => system.readDirectory(path, extensions, excludes, includes, depth),
|
||||
getCurrentDirectory: () => system.getCurrentDirectory(),
|
||||
getDefaultLibFileName: () => ts.projectSystem.libFile.path,
|
||||
getDefaultLibFileName: () => libFile.path,
|
||||
getProjectReferences: () => result.projectReferences,
|
||||
};
|
||||
const ls = ts.createLanguageService(host);
|
||||
@@ -213,21 +214,21 @@ export function Component(x: Config): any;`
|
||||
const { ls, system, class1, class2 } = setup(ts.returnTrue);
|
||||
assert.deepEqual(
|
||||
ls.getProgram()!.getSourceFiles().map(f => f.fileName),
|
||||
[ts.projectSystem.libFile.path, class1.path, class2.path]
|
||||
[libFile.path, class1.path, class2.path]
|
||||
);
|
||||
// Add new file to referenced project
|
||||
const class3 = `${ts.tscWatch.projectRoot}/projects/project1/class3.ts`;
|
||||
const class3 = `/user/username/projects/myproject/projects/project1/class3.ts`;
|
||||
system.writeFile(class3, `class class3 {}`);
|
||||
const program = ls.getProgram()!;
|
||||
assert.deepEqual(
|
||||
program.getSourceFiles().map(f => f.fileName),
|
||||
[ts.projectSystem.libFile.path, class1.path, class3, class2.path]
|
||||
[libFile.path, class1.path, class3, class2.path]
|
||||
);
|
||||
// Add excluded file to referenced project
|
||||
system.ensureFileOrFolder({ path: `${ts.tscWatch.projectRoot}/projects/project1/temp/file.d.ts`, content: `declare class file {}` });
|
||||
system.ensureFileOrFolder({ path: `/user/username/projects/myproject/projects/project1/temp/file.d.ts`, content: `declare class file {}` });
|
||||
assert.strictEqual(ls.getProgram(), program);
|
||||
// Add output from new class to referenced project
|
||||
system.writeFile(`${ts.tscWatch.projectRoot}/projects/project1/class3.d.ts`, `declare class class3 {}`);
|
||||
system.writeFile(`/user/username/projects/myproject/projects/project1/class3.d.ts`, `declare class class3 {}`);
|
||||
assert.strictEqual(ls.getProgram(), program);
|
||||
});
|
||||
|
||||
@@ -236,38 +237,38 @@ export function Component(x: Config): any;`
|
||||
const program1 = ls.getProgram()!;
|
||||
assert.deepEqual(
|
||||
program1.getSourceFiles().map(f => f.fileName),
|
||||
[ts.projectSystem.libFile.path, class1Dts.path, class2.path]
|
||||
[libFile.path, class1Dts.path, class2.path]
|
||||
);
|
||||
// Add new file to referenced project
|
||||
const class3 = `${ts.tscWatch.projectRoot}/projects/project1/class3.ts`;
|
||||
const class3 = `/user/username/projects/myproject/projects/project1/class3.ts`;
|
||||
system.writeFile(class3, `class class3 {}`);
|
||||
assert.notStrictEqual(ls.getProgram(), program1);
|
||||
assert.deepEqual(
|
||||
ls.getProgram()!.getSourceFiles().map(f => f.fileName),
|
||||
[ts.projectSystem.libFile.path, class1Dts.path, class2.path]
|
||||
[libFile.path, class1Dts.path, class2.path]
|
||||
);
|
||||
// Add class3 output
|
||||
const class3Dts = `${ts.tscWatch.projectRoot}/projects/project1/class3.d.ts`;
|
||||
const class3Dts = `/user/username/projects/myproject/projects/project1/class3.d.ts`;
|
||||
system.writeFile(class3Dts, `declare class class3 {}`);
|
||||
const program2 = ls.getProgram()!;
|
||||
assert.deepEqual(
|
||||
program2.getSourceFiles().map(f => f.fileName),
|
||||
[ts.projectSystem.libFile.path, class1Dts.path, class3Dts, class2.path]
|
||||
[libFile.path, class1Dts.path, class3Dts, class2.path]
|
||||
);
|
||||
// Add excluded file to referenced project
|
||||
system.ensureFileOrFolder({ path: `${ts.tscWatch.projectRoot}/projects/project1/temp/file.d.ts`, content: `declare class file {}` });
|
||||
system.ensureFileOrFolder({ path: `/user/username/projects/myproject/projects/project1/temp/file.d.ts`, content: `declare class file {}` });
|
||||
assert.strictEqual(ls.getProgram(), program2);
|
||||
// Delete output from new class to referenced project
|
||||
system.deleteFile(class3Dts);
|
||||
assert.deepEqual(
|
||||
ls.getProgram()!.getSourceFiles().map(f => f.fileName),
|
||||
[ts.projectSystem.libFile.path, class1Dts.path, class2.path]
|
||||
[libFile.path, class1Dts.path, class2.path]
|
||||
);
|
||||
// Write output again
|
||||
system.writeFile(class3Dts, `declare class class3 {}`);
|
||||
assert.deepEqual(
|
||||
ls.getProgram()!.getSourceFiles().map(f => f.fileName),
|
||||
[ts.projectSystem.libFile.path, class1Dts.path, class3Dts, class2.path]
|
||||
[libFile.path, class1Dts.path, class3Dts, class2.path]
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as Harness from "../../_namespaces/Harness";
|
||||
import { createServerHost, File } from "../virtualFileSystemWithWatch";
|
||||
import { createProjectService } from "../tsserver/helpers";
|
||||
import { newLineCharacter } from "./extract/helpers";
|
||||
|
||||
describe("unittests:: services:: organizeImports", () => {
|
||||
describe("Sort imports", () => {
|
||||
@@ -1004,15 +1007,15 @@ export * from "lib";
|
||||
libFile);
|
||||
});
|
||||
|
||||
function testOrganizeExports(testName: string, testFile: ts.TestFSWithWatch.File, ...otherFiles: ts.TestFSWithWatch.File[]) {
|
||||
function testOrganizeExports(testName: string, testFile: File, ...otherFiles: File[]) {
|
||||
testOrganizeImports(`${testName}.exports`, /*skipDestructiveCodeActions*/ true, testFile, ...otherFiles);
|
||||
}
|
||||
|
||||
function testOrganizeImports(testName: string, skipDestructiveCodeActions: boolean, testFile: ts.TestFSWithWatch.File, ...otherFiles: ts.TestFSWithWatch.File[]) {
|
||||
function testOrganizeImports(testName: string, skipDestructiveCodeActions: boolean, testFile: File, ...otherFiles: File[]) {
|
||||
it(testName, () => runBaseline(`organizeImports/${testName}.ts`, skipDestructiveCodeActions, testFile, ...otherFiles));
|
||||
}
|
||||
|
||||
function runBaseline(baselinePath: string, skipDestructiveCodeActions: boolean, testFile: ts.TestFSWithWatch.File, ...otherFiles: ts.TestFSWithWatch.File[]) {
|
||||
function runBaseline(baselinePath: string, skipDestructiveCodeActions: boolean, testFile: File, ...otherFiles: File[]) {
|
||||
const { path: testPath, content: testContent } = testFile;
|
||||
const languageService = makeLanguageService(testFile, ...otherFiles);
|
||||
const changes = languageService.organizeImports({ skipDestructiveCodeActions, type: "file", fileName: testPath }, ts.testFormatSettings, ts.emptyOptions);
|
||||
@@ -1025,12 +1028,12 @@ export * from "lib";
|
||||
testContent,
|
||||
"// ==ORGANIZED==",
|
||||
newText,
|
||||
].join(ts.newLineCharacter));
|
||||
].join(newLineCharacter));
|
||||
}
|
||||
|
||||
function makeLanguageService(...files: ts.TestFSWithWatch.File[]) {
|
||||
const host = ts.projectSystem.createServerHost(files);
|
||||
const projectService = ts.projectSystem.createProjectService(host, { useSingleInferredProject: true });
|
||||
function makeLanguageService(...files: File[]) {
|
||||
const host = createServerHost(files);
|
||||
const projectService = createProjectService(host, { useSingleInferredProject: true });
|
||||
projectService.setCompilerOptionsForInferredProjects({ jsx: files.some(f => f.path.endsWith("x")) ? ts.JsxEmit.React : ts.JsxEmit.None });
|
||||
files.forEach(f => projectService.openClientFile(f.path));
|
||||
return projectService.inferredProjects[0].getLanguageService();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as Harness from "../../_namespaces/Harness";
|
||||
import { notImplementedHost } from "./extract/helpers";
|
||||
|
||||
// Some tests have trailing whitespace
|
||||
|
||||
@@ -21,7 +22,7 @@ describe("unittests:: services:: textChanges", () => {
|
||||
const newLineCharacter = ts.getNewLineCharacter(printerOptions);
|
||||
|
||||
function getRuleProvider(placeOpenBraceOnNewLineForFunctions: boolean): ts.formatting.FormatContext {
|
||||
return ts.formatting.getFormatContext(placeOpenBraceOnNewLineForFunctions ? { ...ts.testFormatSettings, placeOpenBraceOnNewLineForFunctions: true } : ts.testFormatSettings, ts.notImplementedHost);
|
||||
return ts.formatting.getFormatContext(placeOpenBraceOnNewLineForFunctions ? { ...ts.testFormatSettings, placeOpenBraceOnNewLineForFunctions: true } : ts.testFormatSettings, notImplementedHost);
|
||||
}
|
||||
|
||||
// validate that positions that were recovered from the printed text actually match positions that will be created if the same text is parsed.
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as vfs from "../../_namespaces/vfs";
|
||||
import { addRest, addShebang, addSpread, addTestPrologue, addTripleSlashRef, appendText, enableStrict, loadProjectFromDisk, removeRest, replaceText, verifyTsc, verifyTscWithEdits } from "../tsc/helpers";
|
||||
|
||||
describe("unittests:: tsbuild:: outFile:: on amd modules with --out", () => {
|
||||
let outFileFs: vfs.FileSystem;
|
||||
before(() => {
|
||||
outFileFs = ts.loadProjectFromDisk("tests/projects/amdModulesWithOut");
|
||||
outFileFs = loadProjectFromDisk("tests/projects/amdModulesWithOut");
|
||||
});
|
||||
after(() => {
|
||||
outFileFs = undefined!;
|
||||
@@ -21,7 +22,7 @@ describe("unittests:: tsbuild:: outFile:: on amd modules with --out", () => {
|
||||
modifyFs,
|
||||
modifyAgainFs
|
||||
}: VerifyOutFileScenarioInput) {
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "amdModulesWithOut",
|
||||
subScenario,
|
||||
fs: () => outFileFs,
|
||||
@@ -31,7 +32,7 @@ describe("unittests:: tsbuild:: outFile:: on amd modules with --out", () => {
|
||||
edits: [
|
||||
{
|
||||
subScenario: "incremental-declaration-doesnt-change",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/lib/file1.ts", "console.log(x);")
|
||||
modifyFs: fs => appendText(fs, "/src/lib/file1.ts", "console.log(x);")
|
||||
},
|
||||
...(modifyAgainFs ? [{
|
||||
subScenario: "incremental-headers-change-without-dts-changes",
|
||||
@@ -51,15 +52,15 @@ describe("unittests:: tsbuild:: outFile:: on amd modules with --out", () => {
|
||||
verifyOutFileScenario({
|
||||
subScenario: "multiple prologues in all projects",
|
||||
modifyFs: fs => {
|
||||
ts.enableStrict(fs, "/src/lib/tsconfig.json");
|
||||
ts.addTestPrologue(fs, "/src/lib/file0.ts", `"myPrologue"`);
|
||||
ts.addTestPrologue(fs, "/src/lib/file2.ts", `"myPrologueFile"`);
|
||||
ts.addTestPrologue(fs, "/src/lib/global.ts", `"myPrologue3"`);
|
||||
ts.enableStrict(fs, "/src/app/tsconfig.json");
|
||||
ts.addTestPrologue(fs, "/src/app/file3.ts", `"myPrologue"`);
|
||||
ts.addTestPrologue(fs, "/src/app/file4.ts", `"myPrologue2";`);
|
||||
enableStrict(fs, "/src/lib/tsconfig.json");
|
||||
addTestPrologue(fs, "/src/lib/file0.ts", `"myPrologue"`);
|
||||
addTestPrologue(fs, "/src/lib/file2.ts", `"myPrologueFile"`);
|
||||
addTestPrologue(fs, "/src/lib/global.ts", `"myPrologue3"`);
|
||||
enableStrict(fs, "/src/app/tsconfig.json");
|
||||
addTestPrologue(fs, "/src/app/file3.ts", `"myPrologue"`);
|
||||
addTestPrologue(fs, "/src/app/file4.ts", `"myPrologue2";`);
|
||||
},
|
||||
modifyAgainFs: fs => ts.addTestPrologue(fs, "/src/lib/file1.ts", `"myPrologue5"`)
|
||||
modifyAgainFs: fs => addTestPrologue(fs, "/src/lib/file1.ts", `"myPrologue5"`)
|
||||
});
|
||||
});
|
||||
|
||||
@@ -69,9 +70,9 @@ describe("unittests:: tsbuild:: outFile:: on amd modules with --out", () => {
|
||||
verifyOutFileScenario({
|
||||
subScenario: "shebang in all projects",
|
||||
modifyFs: fs => {
|
||||
ts.addShebang(fs, "lib", "file0");
|
||||
ts.addShebang(fs, "lib", "file1");
|
||||
ts.addShebang(fs, "app", "file3");
|
||||
addShebang(fs, "lib", "file0");
|
||||
addShebang(fs, "lib", "file1");
|
||||
addShebang(fs, "app", "file3");
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -81,12 +82,12 @@ describe("unittests:: tsbuild:: outFile:: on amd modules with --out", () => {
|
||||
verifyOutFileScenario({
|
||||
subScenario: "multiple emitHelpers in all projects",
|
||||
modifyFs: fs => {
|
||||
ts.addSpread(fs, "lib", "file0");
|
||||
ts.addRest(fs, "lib", "file1");
|
||||
ts.addRest(fs, "app", "file3");
|
||||
ts.addSpread(fs, "app", "file4");
|
||||
addSpread(fs, "lib", "file0");
|
||||
addRest(fs, "lib", "file1");
|
||||
addRest(fs, "app", "file3");
|
||||
addSpread(fs, "app", "file4");
|
||||
},
|
||||
modifyAgainFs: fs => ts.removeRest(fs, "lib", "file1")
|
||||
modifyAgainFs: fs => removeRest(fs, "lib", "file1")
|
||||
});
|
||||
});
|
||||
|
||||
@@ -96,8 +97,8 @@ describe("unittests:: tsbuild:: outFile:: on amd modules with --out", () => {
|
||||
verifyOutFileScenario({
|
||||
subScenario: "triple slash refs in all projects",
|
||||
modifyFs: fs => {
|
||||
ts.addTripleSlashRef(fs, "lib", "file0");
|
||||
ts.addTripleSlashRef(fs, "app", "file4");
|
||||
addTripleSlashRef(fs, "lib", "file0");
|
||||
addTripleSlashRef(fs, "app", "file4");
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -105,10 +106,10 @@ describe("unittests:: tsbuild:: outFile:: on amd modules with --out", () => {
|
||||
describe("stripInternal", () => {
|
||||
function stripInternalScenario(fs: vfs.FileSystem) {
|
||||
const internal = "/*@internal*/";
|
||||
ts.replaceText(fs, "/src/app/tsconfig.json", `"composite": true,`, `"composite": true,
|
||||
replaceText(fs, "/src/app/tsconfig.json", `"composite": true,`, `"composite": true,
|
||||
"stripInternal": true,`);
|
||||
ts.replaceText(fs, "/src/lib/file0.ts", "const", `${internal} const`);
|
||||
ts.appendText(fs, "/src/lib/file1.ts", `
|
||||
replaceText(fs, "/src/lib/file0.ts", "const", `${internal} const`);
|
||||
appendText(fs, "/src/lib/file1.ts", `
|
||||
export class normalC {
|
||||
${internal} constructor() { }
|
||||
${internal} prop: string;
|
||||
@@ -140,19 +141,19 @@ ${internal} export enum internalEnum { a, b, c }`);
|
||||
verifyOutFileScenario({
|
||||
subScenario: "stripInternal",
|
||||
modifyFs: stripInternalScenario,
|
||||
modifyAgainFs: fs => ts.replaceText(fs, "/src/lib/file1.ts", `export const`, `/*@internal*/ export const`),
|
||||
modifyAgainFs: fs => replaceText(fs, "/src/lib/file1.ts", `export const`, `/*@internal*/ export const`),
|
||||
});
|
||||
});
|
||||
|
||||
describe("when the module resolution finds original source file", () => {
|
||||
function modifyFs(fs: vfs.FileSystem) {
|
||||
// Make lib to output to parent dir
|
||||
ts.replaceText(fs, "/src/lib/tsconfig.json", `"outFile": "module.js"`, `"outFile": "../module.js", "rootDir": "../"`);
|
||||
replaceText(fs, "/src/lib/tsconfig.json", `"outFile": "module.js"`, `"outFile": "../module.js", "rootDir": "../"`);
|
||||
// Change reference to file1 module to resolve to lib/file1
|
||||
ts.replaceText(fs, "/src/app/file3.ts", "file1", "lib/file1");
|
||||
replaceText(fs, "/src/app/file3.ts", "file1", "lib/file1");
|
||||
}
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "amdModulesWithOut",
|
||||
subScenario: "when the module resolution finds original source file",
|
||||
fs: () => outFileFs,
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
|
||||
import { loadProjectFromFiles, verifyTsc } from "../tsc/helpers";
|
||||
describe("unittests:: tsbuild - clean", () => {
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "clean",
|
||||
subScenario: `file name and output name clashing`,
|
||||
commandLineArgs: ["--b", "/src/tsconfig.json", "-clean"],
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/index.js": "",
|
||||
"/src/bar.ts": "",
|
||||
"/src/tsconfig.json": JSON.stringify({
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { appendText, compilerOptionsToConfigJson, loadProjectFromFiles, noChangeRun, noChangeWithExportsDiscrepancyRun, replaceText, TestTscEdit, verifyTscWithEdits } from "../tsc/helpers";
|
||||
|
||||
describe("unittests:: tsbuild:: commandLine::", () => {
|
||||
describe("different options::", () => {
|
||||
function withOptionChange(subScenario: string, ...options: readonly string[]): ts.TestTscEdit {
|
||||
function withOptionChange(subScenario: string, ...options: readonly string[]): TestTscEdit {
|
||||
return {
|
||||
subScenario,
|
||||
modifyFs: ts.noop,
|
||||
commandLineArgs: ["--b", "/src/project", "--verbose", ...options]
|
||||
};
|
||||
}
|
||||
function noChangeWithSubscenario(subScenario: string): ts.TestTscEdit {
|
||||
return { ...ts.noChangeRun, subScenario };
|
||||
function noChangeWithSubscenario(subScenario: string): TestTscEdit {
|
||||
return { ...noChangeRun, subScenario };
|
||||
}
|
||||
function withOptionChangeAndDiscrepancyExplanation(subScenario: string, option: string): ts.TestTscEdit {
|
||||
function withOptionChangeAndDiscrepancyExplanation(subScenario: string, option: string): TestTscEdit {
|
||||
return {
|
||||
...withOptionChange(subScenario, option),
|
||||
discrepancyExplanation: () => [
|
||||
@@ -21,7 +22,7 @@ describe("unittests:: tsbuild:: commandLine::", () => {
|
||||
]
|
||||
};
|
||||
}
|
||||
function withEmitDeclarationOnlyChangeAndDiscrepancyExplanation(subScenario: string): ts.TestTscEdit {
|
||||
function withEmitDeclarationOnlyChangeAndDiscrepancyExplanation(subScenario: string): TestTscEdit {
|
||||
const edit = withOptionChangeAndDiscrepancyExplanation(subScenario, "--emitDeclarationOnly");
|
||||
const discrepancyExplanation = edit.discrepancyExplanation!;
|
||||
edit.discrepancyExplanation = () => [
|
||||
@@ -31,22 +32,22 @@ describe("unittests:: tsbuild:: commandLine::", () => {
|
||||
];
|
||||
return edit;
|
||||
}
|
||||
function withOptionChangeAndExportExplanation(subScenario: string, ...options: readonly string[]): ts.TestTscEdit {
|
||||
function withOptionChangeAndExportExplanation(subScenario: string, ...options: readonly string[]): TestTscEdit {
|
||||
return {
|
||||
...withOptionChange(subScenario, ...options),
|
||||
discrepancyExplanation: ts.noChangeWithExportsDiscrepancyRun.discrepancyExplanation,
|
||||
discrepancyExplanation: noChangeWithExportsDiscrepancyRun.discrepancyExplanation,
|
||||
};
|
||||
}
|
||||
function nochangeWithIncrementalDeclarationFromBeforeExplaination(): ts.TestTscEdit {
|
||||
function nochangeWithIncrementalDeclarationFromBeforeExplaination(): TestTscEdit {
|
||||
return {
|
||||
...ts.noChangeRun,
|
||||
...noChangeRun,
|
||||
discrepancyExplanation: () => [
|
||||
`Clean build tsbuildinfo will have compilerOptions {}`,
|
||||
`Incremental build will detect that it doesnt need to rebuild so tsbuild info is from before which has option declaration and declarationMap`,
|
||||
],
|
||||
};
|
||||
}
|
||||
function nochangeWithIncrementalOutDeclarationFromBeforeExplaination(): ts.TestTscEdit {
|
||||
function nochangeWithIncrementalOutDeclarationFromBeforeExplaination(): TestTscEdit {
|
||||
const edit = nochangeWithIncrementalDeclarationFromBeforeExplaination();
|
||||
const discrepancyExplanation = edit.discrepancyExplanation!;
|
||||
edit.discrepancyExplanation = () => [
|
||||
@@ -56,22 +57,22 @@ describe("unittests:: tsbuild:: commandLine::", () => {
|
||||
];
|
||||
return edit;
|
||||
}
|
||||
function localChange(): ts.TestTscEdit {
|
||||
function localChange(): TestTscEdit {
|
||||
return {
|
||||
subScenario: "local change",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/project/a.ts", "Local = 1", "Local = 10"),
|
||||
modifyFs: fs => replaceText(fs, "/src/project/a.ts", "Local = 1", "Local = 10"),
|
||||
};
|
||||
}
|
||||
function fs(options: ts.CompilerOptions) {
|
||||
return ts.loadProjectFromFiles({
|
||||
"/src/project/tsconfig.json": JSON.stringify({ compilerOptions: ts.compilerOptionsToConfigJson(options) }),
|
||||
return loadProjectFromFiles({
|
||||
"/src/project/tsconfig.json": JSON.stringify({ compilerOptions: compilerOptionsToConfigJson(options) }),
|
||||
"/src/project/a.ts": `export const a = 10;const aLocal = 10;`,
|
||||
"/src/project/b.ts": `export const b = 10;const bLocal = 10;`,
|
||||
"/src/project/c.ts": `import { a } from "./a";export const c = a;`,
|
||||
"/src/project/d.ts": `import { b } from "./b";export const d = b;`,
|
||||
});
|
||||
}
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "commandLine",
|
||||
subScenario: "different options",
|
||||
fs: () => fs({ composite: true }),
|
||||
@@ -80,11 +81,11 @@ describe("unittests:: tsbuild:: commandLine::", () => {
|
||||
withOptionChange("with sourceMap", "--sourceMap"),
|
||||
noChangeWithSubscenario("should re-emit only js so they dont contain sourcemap"),
|
||||
withOptionChangeAndDiscrepancyExplanation("with declaration should not emit anything", "--declaration"),
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
withOptionChange("with declaration and declarationMap", "--declaration", "--declarationMap"),
|
||||
noChangeWithSubscenario("should re-emit only dts so they dont contain sourcemap"),
|
||||
withOptionChangeAndDiscrepancyExplanation("with emitDeclarationOnly should not emit anything", "--emitDeclarationOnly"),
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
localChange(),
|
||||
withOptionChangeAndDiscrepancyExplanation("with declaration should not emit anything", "--declaration"),
|
||||
withOptionChange("with inlineSourceMap", "--inlineSourceMap"),
|
||||
@@ -92,7 +93,7 @@ describe("unittests:: tsbuild:: commandLine::", () => {
|
||||
],
|
||||
baselinePrograms: true,
|
||||
});
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "commandLine",
|
||||
subScenario: "different options with outFile",
|
||||
fs: () => fs({ composite: true, outFile: "../outFile.js", module: ts.ModuleKind.AMD }),
|
||||
@@ -101,11 +102,11 @@ describe("unittests:: tsbuild:: commandLine::", () => {
|
||||
withOptionChange("with sourceMap", "--sourceMap"),
|
||||
noChangeWithSubscenario("should re-emit only js so they dont contain sourcemap"),
|
||||
withOptionChangeAndDiscrepancyExplanation("with declaration should not emit anything", "--declaration"),
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
withOptionChange("with declaration and declarationMap", "--declaration", "--declarationMap"),
|
||||
noChangeWithSubscenario("should re-emit only dts so they dont contain sourcemap"),
|
||||
withEmitDeclarationOnlyChangeAndDiscrepancyExplanation("with emitDeclarationOnly should not emit anything"),
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
localChange(),
|
||||
withOptionChangeAndDiscrepancyExplanation("with declaration should not emit anything", "--declaration"),
|
||||
withOptionChange("with inlineSourceMap", "--inlineSourceMap"),
|
||||
@@ -113,7 +114,7 @@ describe("unittests:: tsbuild:: commandLine::", () => {
|
||||
],
|
||||
baselinePrograms: true,
|
||||
});
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "commandLine",
|
||||
subScenario: "different options with incremental",
|
||||
fs: () => fs({ incremental: true }),
|
||||
@@ -135,7 +136,7 @@ describe("unittests:: tsbuild:: commandLine::", () => {
|
||||
],
|
||||
baselinePrograms: true,
|
||||
});
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "commandLine",
|
||||
subScenario: "different options with incremental with outFile",
|
||||
fs: () => fs({ incremental: true, outFile: "../outFile.js", module: ts.ModuleKind.AMD }),
|
||||
@@ -160,16 +161,16 @@ describe("unittests:: tsbuild:: commandLine::", () => {
|
||||
});
|
||||
describe("emitDeclarationOnly::", () => {
|
||||
function fs(options: ts.CompilerOptions) {
|
||||
return ts.loadProjectFromFiles({
|
||||
return loadProjectFromFiles({
|
||||
"/src/project1/src/tsconfig.json": JSON.stringify({
|
||||
compilerOptions: ts.compilerOptionsToConfigJson(options),
|
||||
compilerOptions: compilerOptionsToConfigJson(options),
|
||||
}),
|
||||
"/src/project1/src/a.ts": `export const a = 10;const aLocal = 10;`,
|
||||
"/src/project1/src/b.ts": `export const b = 10;const bLocal = 10;`,
|
||||
"/src/project1/src/c.ts": `import { a } from "./a";export const c = a;`,
|
||||
"/src/project1/src/d.ts": `import { b } from "./b";export const d = b;`,
|
||||
"/src/project2/src/tsconfig.json": JSON.stringify({
|
||||
compilerOptions: ts.compilerOptionsToConfigJson(options),
|
||||
compilerOptions: compilerOptionsToConfigJson(options),
|
||||
references: [{ path: "../../project1/src" }],
|
||||
}),
|
||||
"/src/project2/src/e.ts": `export const e = 10;`,
|
||||
@@ -178,20 +179,20 @@ describe("unittests:: tsbuild:: commandLine::", () => {
|
||||
});
|
||||
}
|
||||
function verifyWithIncremental(options: ts.CompilerOptions) {
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "commandLine",
|
||||
subScenario: subScenario("emitDeclarationOnly on commandline"),
|
||||
fs: () => fs(options),
|
||||
commandLineArgs: ["--b", "/src/project2/src", "--verbose", "--emitDeclarationOnly"],
|
||||
edits: [
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
{
|
||||
subScenario: "local change",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/project1/src/a.ts", "const aa = 10;"),
|
||||
modifyFs: fs => appendText(fs, "/src/project1/src/a.ts", "const aa = 10;"),
|
||||
},
|
||||
{
|
||||
subScenario: "non local change",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/project1/src/a.ts", "export const aaa = 10;"),
|
||||
modifyFs: fs => appendText(fs, "/src/project1/src/a.ts", "export const aaa = 10;"),
|
||||
},
|
||||
{
|
||||
subScenario: "emit js files",
|
||||
@@ -199,7 +200,7 @@ describe("unittests:: tsbuild:: commandLine::", () => {
|
||||
commandLineArgs: ["--b", "/src/project2/src", "--verbose"],
|
||||
},
|
||||
{
|
||||
...ts.noChangeRun,
|
||||
...noChangeRun,
|
||||
discrepancyExplanation: () => [
|
||||
`Clean build tsbuildinfo for both projects will have compilerOptions with composite and emitDeclarationOnly`,
|
||||
`Incremental build will detect that it doesnt need to rebuild so tsbuild info for projects is from before which has option composite only`,
|
||||
@@ -207,12 +208,12 @@ describe("unittests:: tsbuild:: commandLine::", () => {
|
||||
},
|
||||
{
|
||||
subScenario: "js emit with change without emitDeclarationOnly",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/project1/src/b.ts", "const alocal = 10;"),
|
||||
modifyFs: fs => appendText(fs, "/src/project1/src/b.ts", "const alocal = 10;"),
|
||||
commandLineArgs: ["--b", "/src/project2/src", "--verbose"],
|
||||
},
|
||||
{
|
||||
subScenario: "local change",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/project1/src/b.ts", "const aaaa = 10;"),
|
||||
modifyFs: fs => appendText(fs, "/src/project1/src/b.ts", "const aaaa = 10;"),
|
||||
// --out without composite doesnt emit buildInfo without emitting program so it wouldnt have project2 tsbuildInfo so no mismatch
|
||||
discrepancyExplanation: options.incremental && options.outFile ? undefined : () => [
|
||||
`Clean build tsbuildinfo for project2 will have compilerOptions with composite and emitDeclarationOnly`,
|
||||
@@ -221,26 +222,26 @@ describe("unittests:: tsbuild:: commandLine::", () => {
|
||||
},
|
||||
{
|
||||
subScenario: "non local change",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/project1/src/b.ts", "export const aaaaa = 10;"),
|
||||
modifyFs: fs => appendText(fs, "/src/project1/src/b.ts", "export const aaaaa = 10;"),
|
||||
},
|
||||
{
|
||||
subScenario: "js emit with change without emitDeclarationOnly",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/project1/src/b.ts", "export const a2 = 10;"),
|
||||
modifyFs: fs => appendText(fs, "/src/project1/src/b.ts", "export const a2 = 10;"),
|
||||
commandLineArgs: ["--b", "/src/project2/src", "--verbose"],
|
||||
},
|
||||
],
|
||||
baselinePrograms: true,
|
||||
});
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "commandLine",
|
||||
subScenario: subScenario("emitDeclarationOnly false on commandline"),
|
||||
fs: () => fs({ ...options, emitDeclarationOnly: true }),
|
||||
commandLineArgs: ["--b", "/src/project2/src", "--verbose"],
|
||||
edits: [
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
{
|
||||
subScenario: "change",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/project1/src/a.ts", "const aa = 10;"),
|
||||
modifyFs: fs => appendText(fs, "/src/project1/src/a.ts", "const aa = 10;"),
|
||||
},
|
||||
{
|
||||
subScenario: "emit js files",
|
||||
@@ -248,7 +249,7 @@ describe("unittests:: tsbuild:: commandLine::", () => {
|
||||
commandLineArgs: ["--b", "/src/project2/src", "--verbose", "--emitDeclarationOnly", "false"],
|
||||
},
|
||||
{
|
||||
...ts.noChangeRun,
|
||||
...noChangeRun,
|
||||
discrepancyExplanation: () => [
|
||||
`Clean build tsbuildinfo for both projects will have compilerOptions with composite and emitDeclarationOnly`,
|
||||
`Incremental build will detect that it doesnt need to rebuild so tsbuild info for projects is from before which has option composite as true but emitDeclrationOnly as false`,
|
||||
@@ -261,7 +262,7 @@ describe("unittests:: tsbuild:: commandLine::", () => {
|
||||
},
|
||||
{
|
||||
subScenario: "js emit with change",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/project1/src/b.ts", "const blocal = 10;"),
|
||||
modifyFs: fs => appendText(fs, "/src/project1/src/b.ts", "const blocal = 10;"),
|
||||
commandLineArgs: ["--b", "/src/project2/src", "--verbose", "--emitDeclarationOnly", "false"],
|
||||
},
|
||||
],
|
||||
@@ -276,66 +277,66 @@ describe("unittests:: tsbuild:: commandLine::", () => {
|
||||
verifyWithIncremental({ composite: true, outFile: "../outFile.js", module: ts.ModuleKind.AMD });
|
||||
verifyWithIncremental({ incremental: true, declaration: true, outFile: "../outFile.js", module: ts.ModuleKind.AMD });
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "commandLine",
|
||||
subScenario: "emitDeclarationOnly on commandline with declaration",
|
||||
fs: () => fs({ declaration: true }),
|
||||
commandLineArgs: ["--b", "/src/project2/src", "--verbose", "--emitDeclarationOnly"],
|
||||
edits: [
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
{
|
||||
subScenario: "local change",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/project1/src/a.ts", "const aa = 10;"),
|
||||
modifyFs: fs => appendText(fs, "/src/project1/src/a.ts", "const aa = 10;"),
|
||||
},
|
||||
{
|
||||
subScenario: "non local change",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/project1/src/a.ts", "export const aaa = 10;"),
|
||||
modifyFs: fs => appendText(fs, "/src/project1/src/a.ts", "export const aaa = 10;"),
|
||||
},
|
||||
{
|
||||
subScenario: "emit js files",
|
||||
modifyFs: ts.noop,
|
||||
commandLineArgs: ["--b", "/src/project2/src", "--verbose"],
|
||||
},
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
{
|
||||
subScenario: "js emit with change without emitDeclarationOnly",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/project1/src/b.ts", "const alocal = 10;"),
|
||||
modifyFs: fs => appendText(fs, "/src/project1/src/b.ts", "const alocal = 10;"),
|
||||
commandLineArgs: ["--b", "/src/project2/src", "--verbose"],
|
||||
},
|
||||
{
|
||||
subScenario: "local change",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/project1/src/b.ts", "const aaaa = 10;"),
|
||||
modifyFs: fs => appendText(fs, "/src/project1/src/b.ts", "const aaaa = 10;"),
|
||||
},
|
||||
{
|
||||
subScenario: "non local change",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/project1/src/b.ts", "export const aaaaa = 10;"),
|
||||
modifyFs: fs => appendText(fs, "/src/project1/src/b.ts", "export const aaaaa = 10;"),
|
||||
},
|
||||
{
|
||||
subScenario: "js emit with change without emitDeclarationOnly",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/project1/src/b.ts", "export const a2 = 10;"),
|
||||
modifyFs: fs => appendText(fs, "/src/project1/src/b.ts", "export const a2 = 10;"),
|
||||
commandLineArgs: ["--b", "/src/project2/src", "--verbose"],
|
||||
},
|
||||
],
|
||||
baselinePrograms: true,
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "commandLine",
|
||||
subScenario: "emitDeclarationOnly false on commandline with declaration",
|
||||
fs: () => fs({ declaration: true, emitDeclarationOnly: true }),
|
||||
commandLineArgs: ["--b", "/src/project2/src", "--verbose"],
|
||||
edits: [
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
{
|
||||
subScenario: "change",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/project1/src/a.ts", "const aa = 10;"),
|
||||
modifyFs: fs => appendText(fs, "/src/project1/src/a.ts", "const aa = 10;"),
|
||||
},
|
||||
{
|
||||
subScenario: "emit js files",
|
||||
modifyFs: ts.noop,
|
||||
commandLineArgs: ["--b", "/src/project2/src", "--verbose", "--emitDeclarationOnly", "false"],
|
||||
},
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
{
|
||||
subScenario: "no change run with js emit",
|
||||
modifyFs: ts.noop,
|
||||
@@ -343,73 +344,73 @@ describe("unittests:: tsbuild:: commandLine::", () => {
|
||||
},
|
||||
{
|
||||
subScenario: "js emit with change",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/project1/src/b.ts", "const blocal = 10;"),
|
||||
modifyFs: fs => appendText(fs, "/src/project1/src/b.ts", "const blocal = 10;"),
|
||||
commandLineArgs: ["--b", "/src/project2/src", "--verbose", "--emitDeclarationOnly", "false"],
|
||||
},
|
||||
],
|
||||
baselinePrograms: true,
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "commandLine",
|
||||
subScenario: "emitDeclarationOnly on commandline with declaration with outFile",
|
||||
fs: () => fs({ declaration: true, outFile: "../outFile.js", module: ts.ModuleKind.AMD }),
|
||||
commandLineArgs: ["--b", "/src/project2/src", "--verbose", "--emitDeclarationOnly"],
|
||||
edits: [
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
{
|
||||
subScenario: "local change",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/project1/src/a.ts", "const aa = 10;"),
|
||||
modifyFs: fs => appendText(fs, "/src/project1/src/a.ts", "const aa = 10;"),
|
||||
},
|
||||
{
|
||||
subScenario: "non local change",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/project1/src/a.ts", "export const aaa = 10;"),
|
||||
modifyFs: fs => appendText(fs, "/src/project1/src/a.ts", "export const aaa = 10;"),
|
||||
},
|
||||
{
|
||||
subScenario: "emit js files",
|
||||
modifyFs: ts.noop,
|
||||
commandLineArgs: ["--b", "/src/project2/src", "--verbose"],
|
||||
},
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
{
|
||||
subScenario: "js emit with change without emitDeclarationOnly",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/project1/src/b.ts", "const alocal = 10;"),
|
||||
modifyFs: fs => appendText(fs, "/src/project1/src/b.ts", "const alocal = 10;"),
|
||||
commandLineArgs: ["--b", "/src/project2/src", "--verbose"],
|
||||
},
|
||||
{
|
||||
subScenario: "local change",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/project1/src/b.ts", "const aaaa = 10;"),
|
||||
modifyFs: fs => appendText(fs, "/src/project1/src/b.ts", "const aaaa = 10;"),
|
||||
},
|
||||
{
|
||||
subScenario: "non local change",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/project1/src/b.ts", "export const aaaaa = 10;"),
|
||||
modifyFs: fs => appendText(fs, "/src/project1/src/b.ts", "export const aaaaa = 10;"),
|
||||
},
|
||||
{
|
||||
subScenario: "js emit with change without emitDeclarationOnly",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/project1/src/b.ts", "export const a2 = 10;"),
|
||||
modifyFs: fs => appendText(fs, "/src/project1/src/b.ts", "export const a2 = 10;"),
|
||||
commandLineArgs: ["--b", "/src/project2/src", "--verbose"],
|
||||
},
|
||||
],
|
||||
baselinePrograms: true,
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "commandLine",
|
||||
subScenario: "emitDeclarationOnly false on commandline with declaration with outFile",
|
||||
fs: () => fs({ declaration: true, emitDeclarationOnly: true, outFile: "../outFile.js", module: ts.ModuleKind.AMD }),
|
||||
commandLineArgs: ["--b", "/src/project2/src", "--verbose"],
|
||||
edits: [
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
{
|
||||
subScenario: "change",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/project1/src/a.ts", "const aa = 10;"),
|
||||
modifyFs: fs => appendText(fs, "/src/project1/src/a.ts", "const aa = 10;"),
|
||||
},
|
||||
{
|
||||
subScenario: "emit js files",
|
||||
modifyFs: ts.noop,
|
||||
commandLineArgs: ["--b", "/src/project2/src", "--verbose", "--emitDeclarationOnly", "false"],
|
||||
},
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
{
|
||||
subScenario: "no change run with js emit",
|
||||
modifyFs: ts.noop,
|
||||
@@ -417,7 +418,7 @@ describe("unittests:: tsbuild:: commandLine::", () => {
|
||||
},
|
||||
{
|
||||
subScenario: "js emit with change",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/project1/src/b.ts", "const blocal = 10;"),
|
||||
modifyFs: fs => appendText(fs, "/src/project1/src/b.ts", "const blocal = 10;"),
|
||||
commandLineArgs: ["--b", "/src/project2/src", "--verbose", "--emitDeclarationOnly", "false"],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as Utils from "../../_namespaces/Utils";
|
||||
import { appendText, loadProjectFromDisk, loadProjectFromFiles, noChangeRun, replaceText, verifyTsc, verifyTscWithEdits } from "../tsc/helpers";
|
||||
import { dedent } from "../../_namespaces/Utils";
|
||||
|
||||
describe("unittests:: tsbuild:: configFileErrors:: when tsconfig extends the missing file", () => {
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "configFileErrors",
|
||||
subScenario: "when tsconfig extends the missing file",
|
||||
fs: () => ts.loadProjectFromDisk("tests/projects/missingExtendedConfig"),
|
||||
fs: () => loadProjectFromDisk("tests/projects/missingExtendedConfig"),
|
||||
commandLineArgs: ["--b", "/src/tsconfig.json"],
|
||||
});
|
||||
});
|
||||
|
||||
describe("unittests:: tsbuild:: configFileErrors:: reports syntax errors in config file", () => {
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "configFileErrors",
|
||||
subScenario: "reports syntax errors in config file",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/a.ts": "export function foo() { }",
|
||||
"/src/b.ts": "export function bar() { }",
|
||||
"/src/tsconfig.json": Utils.dedent`
|
||||
"/src/tsconfig.json": dedent`
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
@@ -31,7 +31,7 @@ describe("unittests:: tsbuild:: configFileErrors:: reports syntax errors in conf
|
||||
commandLineArgs: ["--b", "/src/tsconfig.json"],
|
||||
edits: [
|
||||
{
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/tsconfig.json", ",", `,
|
||||
modifyFs: fs => replaceText(fs, "/src/tsconfig.json", ",", `,
|
||||
"declaration": true,`),
|
||||
subScenario: "reports syntax errors after change to config file",
|
||||
discrepancyExplanation: () => [
|
||||
@@ -40,10 +40,10 @@ describe("unittests:: tsbuild:: configFileErrors:: reports syntax errors in conf
|
||||
],
|
||||
},
|
||||
{
|
||||
modifyFs: fs => ts.appendText(fs, "/src/a.ts", "export function fooBar() { }"),
|
||||
modifyFs: fs => appendText(fs, "/src/a.ts", "export function fooBar() { }"),
|
||||
subScenario: "reports syntax errors after change to ts file",
|
||||
},
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
{
|
||||
modifyFs: fs => fs.writeFileSync(
|
||||
"/src/tsconfig.json",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { loadProjectFromFiles, verifyTsc } from "../tsc/helpers";
|
||||
|
||||
describe("unittests:: tsbuild:: configFileExtends:: when tsconfig extends another config", () => {
|
||||
function getConfigExtendsWithIncludeFs() {
|
||||
return ts.loadProjectFromFiles({
|
||||
return loadProjectFromFiles({
|
||||
"/src/tsconfig.json": JSON.stringify({
|
||||
references: [
|
||||
{ path: "./shared/tsconfig.json" },
|
||||
@@ -37,13 +37,13 @@ describe("unittests:: tsbuild:: configFileExtends:: when tsconfig extends anothe
|
||||
"/src/webpack/index.ts": `export const b: Unrestricted = 1;`,
|
||||
});
|
||||
}
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "configFileExtends",
|
||||
subScenario: "when building solution with projects extends config with include",
|
||||
fs: getConfigExtendsWithIncludeFs,
|
||||
commandLineArgs: ["--b", "/src/tsconfig.json", "--v", "--listFiles"],
|
||||
});
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "configFileExtends",
|
||||
subScenario: "when building project uses reference and both extend config with include",
|
||||
fs: getConfigExtendsWithIncludeFs,
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { loadProjectFromDisk, loadProjectFromFiles, noChangeOnlyRuns, replaceText, verifyTscWithEdits } from "../tsc/helpers";
|
||||
|
||||
describe("unittests:: tsbuild:: when containerOnly project is referenced", () => {
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "containerOnlyReferenced",
|
||||
subScenario: "verify that subsequent builds after initial build doesnt build anything",
|
||||
fs: () => ts.loadProjectFromDisk("tests/projects/containerOnlyReferenced"),
|
||||
fs: () => loadProjectFromDisk("tests/projects/containerOnlyReferenced"),
|
||||
commandLineArgs: ["--b", "/src", "--verbose"],
|
||||
edits: ts.noChangeOnlyRuns
|
||||
edits: noChangeOnlyRuns
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "containerOnlyReferenced",
|
||||
subScenario: "when solution is referenced indirectly",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/project1/tsconfig.json": JSON.stringify({
|
||||
compilerOptions: { composite: true },
|
||||
references: [],
|
||||
@@ -36,7 +36,7 @@ describe("unittests:: tsbuild:: when containerOnly project is referenced", () =>
|
||||
commandLineArgs: ["--b", "/src/project4", "--verbose", "--explainFiles"],
|
||||
edits: [{
|
||||
subScenario: "modify project3 file",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/project3/src/c.ts", "c = ", "cc = "),
|
||||
modifyFs: fs => replaceText(fs, "/src/project3/src/c.ts", "c = ", "cc = "),
|
||||
}],
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as vfs from "../../_namespaces/vfs";
|
||||
import * as Utils from "../../_namespaces/Utils";
|
||||
import { loadProjectFromFiles, verifyTsc } from "../tsc/helpers";
|
||||
|
||||
describe("unittests:: tsbuild:: declarationEmit", () => {
|
||||
function getFiles(): vfs.FileSet {
|
||||
@@ -58,17 +58,17 @@ declare type MyNominal<T, Name extends string> = T & {
|
||||
};`,
|
||||
};
|
||||
}
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "declarationEmit",
|
||||
subScenario: "when declaration file is referenced through triple slash",
|
||||
fs: () => ts.loadProjectFromFiles(getFiles()),
|
||||
fs: () => loadProjectFromFiles(getFiles()),
|
||||
commandLineArgs: ["--b", "/src/solution/tsconfig.json", "--verbose"]
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "declarationEmit",
|
||||
subScenario: "when declaration file is referenced through triple slash but uses no references",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
...getFiles(),
|
||||
"/src/solution/tsconfig.json": JSON.stringify({
|
||||
extends: "./tsconfig.base.json",
|
||||
@@ -79,10 +79,10 @@ declare type MyNominal<T, Name extends string> = T & {
|
||||
commandLineArgs: ["--b", "/src/solution/tsconfig.json", "--verbose"]
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "declarationEmit",
|
||||
subScenario: "when declaration file used inferred type from referenced project",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/tsconfig.json": JSON.stringify({
|
||||
compilerOptions: {
|
||||
composite: true,
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as vfs from "../../_namespaces/vfs";
|
||||
import { loadProjectFromDisk, prependText, replaceText, verifyTsc } from "../tsc/helpers";
|
||||
|
||||
describe("unittests:: tsbuild:: on demo project", () => {
|
||||
let projFs: vfs.FileSystem;
|
||||
before(() => {
|
||||
projFs = ts.loadProjectFromDisk("tests/projects/demo");
|
||||
projFs = loadProjectFromDisk("tests/projects/demo");
|
||||
});
|
||||
|
||||
after(() => {
|
||||
projFs = undefined!; // Release the contents
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "demo",
|
||||
subScenario: "in master branch with everything setup correctly and reports no error",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "/src/tsconfig.json", "--verbose"]
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "demo",
|
||||
subScenario: "in circular branch reports the error about it by stopping build",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "/src/tsconfig.json", "--verbose"],
|
||||
modifyFs: fs => ts.replaceText(
|
||||
modifyFs: fs => replaceText(
|
||||
fs,
|
||||
"/src/core/tsconfig.json",
|
||||
"}",
|
||||
@@ -35,12 +35,12 @@ describe("unittests:: tsbuild:: on demo project", () => {
|
||||
]`
|
||||
)
|
||||
});
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "demo",
|
||||
subScenario: "in bad-ref branch reports the error about files not in rootDir at the import location",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "/src/tsconfig.json", "--verbose"],
|
||||
modifyFs: fs => ts.prependText(
|
||||
modifyFs: fs => prependText(
|
||||
fs,
|
||||
"/src/core/utilities.ts",
|
||||
`import * as A from '../animals';
|
||||
|
||||
@@ -1,52 +1,52 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as vfs from "../../_namespaces/vfs";
|
||||
import { loadProjectFromDisk, replaceText, verifyTscWithEdits } from "../tsc/helpers";
|
||||
|
||||
describe("unittests:: tsbuild:: on project with emitDeclarationOnly set to true", () => {
|
||||
let projFs: vfs.FileSystem;
|
||||
before(() => {
|
||||
projFs = ts.loadProjectFromDisk("tests/projects/emitDeclarationOnly");
|
||||
projFs = loadProjectFromDisk("tests/projects/emitDeclarationOnly");
|
||||
});
|
||||
after(() => {
|
||||
projFs = undefined!;
|
||||
});
|
||||
|
||||
function verifyEmitDeclarationOnly(disableMap?: true) {
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
subScenario: `only dts output in circular import project with emitDeclarationOnly${disableMap ? "" : " and declarationMap"}`,
|
||||
fs: () => projFs,
|
||||
scenario: "emitDeclarationOnly",
|
||||
commandLineArgs: ["--b", "/src", "--verbose"],
|
||||
modifyFs: disableMap ?
|
||||
(fs => ts.replaceText(fs, "/src/tsconfig.json", `"declarationMap": true,`, "")) :
|
||||
(fs => replaceText(fs, "/src/tsconfig.json", `"declarationMap": true,`, "")) :
|
||||
undefined,
|
||||
edits: [{
|
||||
subScenario: "incremental-declaration-changes",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/src/a.ts", "b: B;", "b: B; foo: any;"),
|
||||
modifyFs: fs => replaceText(fs, "/src/src/a.ts", "b: B;", "b: B; foo: any;"),
|
||||
}],
|
||||
});
|
||||
}
|
||||
verifyEmitDeclarationOnly();
|
||||
verifyEmitDeclarationOnly(/*disableMap*/ true);
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
subScenario: `only dts output in non circular imports project with emitDeclarationOnly`,
|
||||
fs: () => projFs,
|
||||
scenario: "emitDeclarationOnly",
|
||||
commandLineArgs: ["--b", "/src", "--verbose"],
|
||||
modifyFs: fs => {
|
||||
fs.rimrafSync("/src/src/index.ts");
|
||||
ts.replaceText(fs, "/src/src/a.ts", `import { B } from "./b";`, `export class B { prop = "hello"; }`);
|
||||
replaceText(fs, "/src/src/a.ts", `import { B } from "./b";`, `export class B { prop = "hello"; }`);
|
||||
},
|
||||
edits: [
|
||||
{
|
||||
subScenario: "incremental-declaration-doesnt-change",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/src/a.ts", "export interface A {", `class C { }
|
||||
modifyFs: fs => replaceText(fs, "/src/src/a.ts", "export interface A {", `class C { }
|
||||
export interface A {`),
|
||||
|
||||
},
|
||||
{
|
||||
subScenario: "incremental-declaration-changes",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/src/a.ts", "b: B;", "b: B; foo: any;"),
|
||||
modifyFs: fs => replaceText(fs, "/src/src/a.ts", "b: B;", "b: B; foo: any;"),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as vfs from "../../_namespaces/vfs";
|
||||
import { loadProjectFromDisk, verifyTsc } from "../tsc/helpers";
|
||||
|
||||
describe("unittests:: tsbuild - empty files option in tsconfig", () => {
|
||||
let projFs: vfs.FileSystem;
|
||||
before(() => {
|
||||
projFs = ts.loadProjectFromDisk("tests/projects/empty-files");
|
||||
projFs = loadProjectFromDisk("tests/projects/empty-files");
|
||||
});
|
||||
after(() => {
|
||||
projFs = undefined!;
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "emptyFiles",
|
||||
subScenario: "has empty files diagnostic when files is empty and no references are provided",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "/src/no-references"],
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "emptyFiles",
|
||||
subScenario: "does not have empty files diagnostic when files is empty and references are provided",
|
||||
fs: () => projFs,
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { loadProjectFromFiles, verifyTsc } from "../tsc/helpers";
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/33849
|
||||
describe("unittests:: tsbuild:: exitCodeOnBogusFile:: test exit code", () => {
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "exitCodeOnBogusFile",
|
||||
subScenario: `test exit code`,
|
||||
fs: () => ts.loadProjectFromFiles({}),
|
||||
fs: () => loadProjectFromFiles({}),
|
||||
commandLineArgs: ["-b", "bogus.json"]
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,769 +0,0 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as fakes from "../../_namespaces/fakes";
|
||||
import * as vfs from "../../_namespaces/vfs";
|
||||
import * as Harness from "../../_namespaces/Harness";
|
||||
import * as vpath from "../../_namespaces/vpath";
|
||||
|
||||
export function errorDiagnostic(message: fakes.ExpectedDiagnosticMessage): fakes.ExpectedErrorDiagnostic {
|
||||
return { message };
|
||||
}
|
||||
|
||||
export function getExpectedDiagnosticForProjectsInBuild(...projects: string[]): fakes.ExpectedDiagnostic {
|
||||
return [ts.Diagnostics.Projects_in_this_build_Colon_0, projects.map(p => "\r\n * " + p).join("")];
|
||||
}
|
||||
|
||||
export function changeCompilerVersion(host: fakes.SolutionBuilderHost) {
|
||||
const originalReadFile = host.readFile;
|
||||
host.readFile = path => {
|
||||
const value = originalReadFile.call(host, path);
|
||||
if (!value || !ts.isBuildInfoFile(path)) return value;
|
||||
const buildInfo = ts.getBuildInfo(path, value);
|
||||
if (!buildInfo) return value;
|
||||
buildInfo.version = fakes.version;
|
||||
return ts.getBuildInfoText(buildInfo);
|
||||
};
|
||||
}
|
||||
|
||||
export function replaceText(fs: vfs.FileSystem, path: string, oldText: string, newText: string) {
|
||||
if (!fs.statSync(path).isFile()) {
|
||||
throw new Error(`File ${path} does not exist`);
|
||||
}
|
||||
const old = fs.readFileSync(path, "utf-8");
|
||||
if (old.indexOf(oldText) < 0) {
|
||||
throw new Error(`Text "${oldText}" does not exist in file ${path}`);
|
||||
}
|
||||
const newContent = old.replace(oldText, newText);
|
||||
fs.writeFileSync(path, newContent, "utf-8");
|
||||
}
|
||||
|
||||
export function prependText(fs: vfs.FileSystem, path: string, additionalContent: string) {
|
||||
if (!fs.statSync(path).isFile()) {
|
||||
throw new Error(`File ${path} does not exist`);
|
||||
}
|
||||
const old = fs.readFileSync(path, "utf-8");
|
||||
fs.writeFileSync(path, `${additionalContent}${old}`, "utf-8");
|
||||
}
|
||||
|
||||
export function appendText(fs: vfs.FileSystem, path: string, additionalContent: string) {
|
||||
if (!fs.statSync(path).isFile()) {
|
||||
throw new Error(`File ${path} does not exist`);
|
||||
}
|
||||
const old = fs.readFileSync(path, "utf-8");
|
||||
fs.writeFileSync(path, `${old}${additionalContent}`);
|
||||
}
|
||||
|
||||
export function indexOf(fs: vfs.FileSystem, path: string, searchStr: string) {
|
||||
if (!fs.statSync(path).isFile()) {
|
||||
throw new Error(`File ${path} does not exist`);
|
||||
}
|
||||
const content = fs.readFileSync(path, "utf-8");
|
||||
return content.indexOf(searchStr);
|
||||
}
|
||||
|
||||
export function lastIndexOf(fs: vfs.FileSystem, path: string, searchStr: string) {
|
||||
if (!fs.statSync(path).isFile()) {
|
||||
throw new Error(`File ${path} does not exist`);
|
||||
}
|
||||
const content = fs.readFileSync(path, "utf-8");
|
||||
return content.lastIndexOf(searchStr);
|
||||
}
|
||||
|
||||
export function expectedLocationIndexOf(fs: vfs.FileSystem, file: string, searchStr: string): fakes.ExpectedDiagnosticLocation {
|
||||
return {
|
||||
file,
|
||||
start: indexOf(fs, file, searchStr),
|
||||
length: searchStr.length
|
||||
};
|
||||
}
|
||||
|
||||
export function expectedLocationLastIndexOf(fs: vfs.FileSystem, file: string, searchStr: string): fakes.ExpectedDiagnosticLocation {
|
||||
return {
|
||||
file,
|
||||
start: lastIndexOf(fs, file, searchStr),
|
||||
length: searchStr.length
|
||||
};
|
||||
}
|
||||
|
||||
export const libContent = `${ts.TestFSWithWatch.libFile.content}
|
||||
interface ReadonlyArray<T> {}
|
||||
declare const console: { log(msg: any): void; };`;
|
||||
|
||||
export const symbolLibContent = `
|
||||
interface SymbolConstructor {
|
||||
readonly species: symbol;
|
||||
readonly toStringTag: symbol;
|
||||
}
|
||||
declare var Symbol: SymbolConstructor;
|
||||
interface Symbol {
|
||||
readonly [Symbol.toStringTag]: string;
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* Load project from disk into /src folder
|
||||
*/
|
||||
export function loadProjectFromDisk(
|
||||
root: string,
|
||||
libContentToAppend?: string
|
||||
): vfs.FileSystem {
|
||||
const resolver = vfs.createResolver(Harness.IO);
|
||||
const fs = new vfs.FileSystem(/*ignoreCase*/ true, {
|
||||
files: {
|
||||
["/src"]: new vfs.Mount(vpath.resolve(Harness.IO.getWorkspaceRoot(), root), resolver)
|
||||
},
|
||||
cwd: "/",
|
||||
meta: { defaultLibLocation: "/lib" },
|
||||
});
|
||||
addLibAndMakeReadonly(fs, libContentToAppend);
|
||||
return fs;
|
||||
}
|
||||
|
||||
/**
|
||||
* All the files must be in /src
|
||||
*/
|
||||
export function loadProjectFromFiles(
|
||||
files: vfs.FileSet,
|
||||
libContentToAppend?: string
|
||||
): vfs.FileSystem {
|
||||
const fs = new vfs.FileSystem(/*ignoreCase*/ true, {
|
||||
files,
|
||||
cwd: "/",
|
||||
meta: { defaultLibLocation: "/lib" },
|
||||
});
|
||||
addLibAndMakeReadonly(fs, libContentToAppend);
|
||||
return fs;
|
||||
}
|
||||
|
||||
function addLibAndMakeReadonly(fs: vfs.FileSystem, libContentToAppend?: string) {
|
||||
fs.mkdirSync("/lib");
|
||||
fs.writeFileSync("/lib/lib.d.ts", libContentToAppend ? `${libContent}${libContentToAppend}` : libContent);
|
||||
fs.makeReadonly();
|
||||
}
|
||||
|
||||
export function verifyOutputsPresent(fs: vfs.FileSystem, outputs: readonly string[]) {
|
||||
for (const output of outputs) {
|
||||
assert(fs.existsSync(output), `Expect file ${output} to exist`);
|
||||
}
|
||||
}
|
||||
|
||||
export function verifyOutputsAbsent(fs: vfs.FileSystem, outputs: readonly string[]) {
|
||||
for (const output of outputs) {
|
||||
assert.isFalse(fs.existsSync(output), `Expect file ${output} to not exist`);
|
||||
}
|
||||
}
|
||||
|
||||
export function generateSourceMapBaselineFiles(sys: ts.System & { writtenFiles: ts.ReadonlyCollection<ts.Path>; }) {
|
||||
const mapFileNames = ts.mapDefinedIterator(sys.writtenFiles.keys(), f => f.endsWith(".map") ? f : undefined);
|
||||
while (true) {
|
||||
const result = mapFileNames.next();
|
||||
if (result.done) break;
|
||||
const mapFile = result.value;
|
||||
const text = Harness.SourceMapRecorder.getSourceMapRecordWithSystem(sys, mapFile);
|
||||
sys.writeFile(`${mapFile}.baseline.txt`, text);
|
||||
}
|
||||
}
|
||||
|
||||
function generateBundleFileSectionInfo(sys: ts.System, originalReadCall: ts.System["readFile"], baselineRecorder: Harness.Compiler.WriterAggregator, bundleFileInfo: ts.BundleFileInfo | undefined, outFile: string | undefined) {
|
||||
if (!ts.length(bundleFileInfo && bundleFileInfo.sections) && !outFile) return; // Nothing to baseline
|
||||
|
||||
const content = outFile && sys.fileExists(outFile) ? originalReadCall.call(sys, outFile, "utf8")! : "";
|
||||
baselineRecorder.WriteLine("======================================================================");
|
||||
baselineRecorder.WriteLine(`File:: ${outFile}`);
|
||||
for (const section of bundleFileInfo ? bundleFileInfo.sections : ts.emptyArray) {
|
||||
baselineRecorder.WriteLine("----------------------------------------------------------------------");
|
||||
writeSectionHeader(section);
|
||||
if (section.kind !== ts.BundleFileSectionKind.Prepend) {
|
||||
writeTextOfSection(section.pos, section.end);
|
||||
}
|
||||
else if (section.texts.length > 0) {
|
||||
ts.Debug.assert(section.pos === ts.first(section.texts).pos);
|
||||
ts.Debug.assert(section.end === ts.last(section.texts).end);
|
||||
for (const text of section.texts) {
|
||||
baselineRecorder.WriteLine(">>--------------------------------------------------------------------");
|
||||
writeSectionHeader(text);
|
||||
writeTextOfSection(text.pos, text.end);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ts.Debug.assert(section.pos === section.end);
|
||||
}
|
||||
}
|
||||
baselineRecorder.WriteLine("======================================================================");
|
||||
|
||||
function writeTextOfSection(pos: number, end: number) {
|
||||
const textLines = content.substring(pos, end).split(/\r?\n/);
|
||||
for (const line of textLines) {
|
||||
baselineRecorder.WriteLine(line);
|
||||
}
|
||||
}
|
||||
|
||||
function writeSectionHeader(section: ts.BundleFileSection) {
|
||||
baselineRecorder.WriteLine(`${section.kind}: (${section.pos}-${section.end})${section.data ? ":: " + section.data : ""}${section.kind === ts.BundleFileSectionKind.Prepend ? " texts:: " + section.texts.length : ""}`);
|
||||
}
|
||||
}
|
||||
|
||||
type ReadableProgramBuildInfoDiagnostic = string | [string, readonly ts.ReusableDiagnostic[]];
|
||||
type ReadableBuilderFileEmit = string & { __readableBuilderFileEmit: any; };
|
||||
type ReadableProgramBuilderInfoFilePendingEmit = [original: string | [string], emitKind: ReadableBuilderFileEmit];
|
||||
type ReadableProgramBuildInfoEmitSignature = string | [string, ts.EmitSignature | []];
|
||||
type ReadableProgramBuildInfoFileInfo<T> = Omit<ts.BuilderState.FileInfo, "impliedFormat"> & {
|
||||
impliedFormat: string | undefined;
|
||||
original: T | undefined;
|
||||
};
|
||||
type ReadableProgramMultiFileEmitBuildInfo = Omit<ts.ProgramMultiFileEmitBuildInfo,
|
||||
"fileIdsList" | "fileInfos" |
|
||||
"referencedMap" | "exportedModulesMap" | "semanticDiagnosticsPerFile" |
|
||||
"affectedFilesPendingEmit" | "changeFileSet" | "emitSignatures"
|
||||
> & {
|
||||
fileNamesList: readonly (readonly string[])[] | undefined;
|
||||
fileInfos: ts.MapLike<ReadableProgramBuildInfoFileInfo<ts.ProgramMultiFileEmitBuildInfoFileInfo>>;
|
||||
referencedMap: ts.MapLike<string[]> | undefined;
|
||||
exportedModulesMap: ts.MapLike<string[]> | undefined;
|
||||
semanticDiagnosticsPerFile: readonly ReadableProgramBuildInfoDiagnostic[] | undefined;
|
||||
affectedFilesPendingEmit: readonly ReadableProgramBuilderInfoFilePendingEmit[] | undefined;
|
||||
changeFileSet: readonly string[] | undefined;
|
||||
emitSignatures: readonly ReadableProgramBuildInfoEmitSignature[] | undefined;
|
||||
};
|
||||
type ReadableProgramBuildInfoBundlePendingEmit = [emitKind: ReadableBuilderFileEmit, original: ts.ProgramBuildInfoBundlePendingEmit];
|
||||
type ReadableProgramBundleEmitBuildInfo = Omit<ts.ProgramBundleEmitBuildInfo, "fileInfos" | "pendingEmit"> & {
|
||||
fileInfos: ts.MapLike<string | ReadableProgramBuildInfoFileInfo<ts.BuilderState.FileInfo>>;
|
||||
pendingEmit: ReadableProgramBuildInfoBundlePendingEmit | undefined;
|
||||
};
|
||||
|
||||
type ReadableProgramBuildInfo = ReadableProgramMultiFileEmitBuildInfo | ReadableProgramBundleEmitBuildInfo;
|
||||
|
||||
function isReadableProgramBundleEmitBuildInfo(info: ReadableProgramBuildInfo | undefined): info is ReadableProgramBundleEmitBuildInfo {
|
||||
return !!info && !!ts.outFile(info.options || {});
|
||||
}
|
||||
type ReadableBuildInfo = Omit<ts.BuildInfo, "program"> & { program: ReadableProgramBuildInfo | undefined; size: number; };
|
||||
function generateBuildInfoProgramBaseline(sys: ts.System, buildInfoPath: string, buildInfo: ts.BuildInfo) {
|
||||
let program: ReadableProgramBuildInfo | undefined;
|
||||
let fileNamesList: string[][] | undefined;
|
||||
if (buildInfo.program && ts.isProgramBundleEmitBuildInfo(buildInfo.program)) {
|
||||
const fileInfos: ReadableProgramBundleEmitBuildInfo["fileInfos"] = {};
|
||||
buildInfo.program?.fileInfos?.forEach((fileInfo, index) =>
|
||||
fileInfos[toFileName(index + 1 as ts.ProgramBuildInfoFileId)] = ts.isString(fileInfo) ?
|
||||
fileInfo :
|
||||
toReadableFileInfo(fileInfo, ts.identity)
|
||||
);
|
||||
const pendingEmit = buildInfo.program.pendingEmit;
|
||||
program = {
|
||||
...buildInfo.program,
|
||||
fileInfos,
|
||||
pendingEmit: pendingEmit === undefined ?
|
||||
undefined :
|
||||
[
|
||||
toReadableBuilderFileEmit(ts.toProgramEmitPending(pendingEmit, buildInfo.program.options)),
|
||||
pendingEmit
|
||||
],
|
||||
};
|
||||
}
|
||||
else if (buildInfo.program) {
|
||||
const fileInfos: ReadableProgramMultiFileEmitBuildInfo["fileInfos"] = {};
|
||||
buildInfo.program?.fileInfos?.forEach((fileInfo, index) => fileInfos[toFileName(index + 1 as ts.ProgramBuildInfoFileId)] = toReadableFileInfo(fileInfo, ts.toBuilderStateFileInfoForMultiEmit));
|
||||
fileNamesList = buildInfo.program.fileIdsList?.map(fileIdsListId => fileIdsListId.map(toFileName));
|
||||
const fullEmitForOptions = buildInfo.program.affectedFilesPendingEmit ? ts.getBuilderFileEmit(buildInfo.program.options || {}) : undefined;
|
||||
program = buildInfo.program && {
|
||||
fileNames: buildInfo.program.fileNames,
|
||||
fileNamesList,
|
||||
fileInfos: buildInfo.program.fileInfos ? fileInfos : undefined!,
|
||||
options: buildInfo.program.options,
|
||||
referencedMap: toMapOfReferencedSet(buildInfo.program.referencedMap),
|
||||
exportedModulesMap: toMapOfReferencedSet(buildInfo.program.exportedModulesMap),
|
||||
semanticDiagnosticsPerFile: buildInfo.program.semanticDiagnosticsPerFile?.map(d =>
|
||||
ts.isNumber(d) ?
|
||||
toFileName(d) :
|
||||
[toFileName(d[0]), d[1]]
|
||||
),
|
||||
affectedFilesPendingEmit: buildInfo.program.affectedFilesPendingEmit?.map(value => toReadableProgramBuilderInfoFilePendingEmit(value, fullEmitForOptions!)),
|
||||
changeFileSet: buildInfo.program.changeFileSet?.map(toFileName),
|
||||
emitSignatures: buildInfo.program.emitSignatures?.map(s =>
|
||||
ts.isNumber(s) ?
|
||||
toFileName(s) :
|
||||
[toFileName(s[0]), s[1]]
|
||||
),
|
||||
latestChangedDtsFile: buildInfo.program.latestChangedDtsFile,
|
||||
};
|
||||
}
|
||||
const version = buildInfo.version === ts.version ? fakes.version : buildInfo.version;
|
||||
const result: ReadableBuildInfo = {
|
||||
// Baseline fixed order for bundle
|
||||
bundle: buildInfo.bundle && {
|
||||
...buildInfo.bundle,
|
||||
js: buildInfo.bundle.js && {
|
||||
sections: buildInfo.bundle.js.sections,
|
||||
hash: buildInfo.bundle.js.hash,
|
||||
mapHash: buildInfo.bundle.js.mapHash,
|
||||
sources: buildInfo.bundle.js.sources,
|
||||
},
|
||||
dts: buildInfo.bundle.dts && {
|
||||
sections: buildInfo.bundle.dts.sections,
|
||||
hash: buildInfo.bundle.dts.hash,
|
||||
mapHash: buildInfo.bundle.dts.mapHash,
|
||||
sources: buildInfo.bundle.dts.sources,
|
||||
},
|
||||
},
|
||||
program,
|
||||
version,
|
||||
size: ts.getBuildInfoText({ ...buildInfo, version }).length,
|
||||
};
|
||||
// For now its just JSON.stringify
|
||||
sys.writeFile(`${buildInfoPath}.readable.baseline.txt`, JSON.stringify(result, /*replacer*/ undefined, 2));
|
||||
|
||||
function toFileName(fileId: ts.ProgramBuildInfoFileId) {
|
||||
return buildInfo.program!.fileNames[fileId - 1];
|
||||
}
|
||||
|
||||
function toFileNames(fileIdsListId: ts.ProgramBuildInfoFileIdListId) {
|
||||
return fileNamesList![fileIdsListId - 1];
|
||||
}
|
||||
|
||||
function toReadableFileInfo<T>(original: T, toFileInfo: (fileInfo: T) => ts.BuilderState.FileInfo): ReadableProgramBuildInfoFileInfo<T> {
|
||||
const info = toFileInfo(original);
|
||||
return {
|
||||
original: ts.isString(original) ? undefined : original,
|
||||
...info,
|
||||
impliedFormat: info.impliedFormat && ts.getNameOfCompilerOptionValue(info.impliedFormat, ts.moduleOptionDeclaration.type),
|
||||
};
|
||||
}
|
||||
|
||||
function toMapOfReferencedSet(referenceMap: ts.ProgramBuildInfoReferencedMap | undefined): ts.MapLike<string[]> | undefined {
|
||||
if (!referenceMap) return undefined;
|
||||
const result: ts.MapLike<string[]> = {};
|
||||
for (const [fileNamesKey, fileNamesListKey] of referenceMap) {
|
||||
result[toFileName(fileNamesKey)] = toFileNames(fileNamesListKey);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function toReadableProgramBuilderInfoFilePendingEmit(value: ts.ProgramBuilderInfoFilePendingEmit, fullEmitForOptions: ts.BuilderFileEmit): ReadableProgramBuilderInfoFilePendingEmit {
|
||||
return [
|
||||
ts.isNumber(value) ? toFileName(value) : [toFileName(value[0])],
|
||||
toReadableBuilderFileEmit(ts.toBuilderFileEmit(value, fullEmitForOptions)),
|
||||
];
|
||||
}
|
||||
|
||||
function toReadableBuilderFileEmit(emit: ts.BuilderFileEmit | undefined): ReadableBuilderFileEmit {
|
||||
let result = "";
|
||||
if (emit) {
|
||||
if (emit & ts.BuilderFileEmit.Js) addFlags("Js");
|
||||
if (emit & ts.BuilderFileEmit.JsMap) addFlags("JsMap");
|
||||
if (emit & ts.BuilderFileEmit.JsInlineMap) addFlags("JsInlineMap");
|
||||
if (emit & ts.BuilderFileEmit.Dts) addFlags("Dts");
|
||||
if (emit & ts.BuilderFileEmit.DtsMap) addFlags("DtsMap");
|
||||
}
|
||||
return (result || "None") as ReadableBuilderFileEmit;
|
||||
function addFlags(flag: string) {
|
||||
result = result ? `${result} | ${flag}` : flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function toPathWithSystem(sys: ts.System, fileName: string): ts.Path {
|
||||
return ts.toPath(fileName, sys.getCurrentDirectory(), ts.createGetCanonicalFileName(sys.useCaseSensitiveFileNames));
|
||||
}
|
||||
|
||||
export function baselineBuildInfo(
|
||||
options: ts.CompilerOptions,
|
||||
sys: ts.TscCompileSystem | ts.tscWatch.WatchedSystem,
|
||||
originalReadCall?: ts.System["readFile"],
|
||||
) {
|
||||
const buildInfoPath = ts.getTsBuildInfoEmitOutputFilePath(options);
|
||||
if (!buildInfoPath || !sys.writtenFiles!.has(toPathWithSystem(sys, buildInfoPath))) return;
|
||||
if (!sys.fileExists(buildInfoPath)) return;
|
||||
|
||||
const buildInfo = ts.getBuildInfo(buildInfoPath, (originalReadCall || sys.readFile).call(sys, buildInfoPath, "utf8")!);
|
||||
if (!buildInfo) return sys.writeFile(`${buildInfoPath}.baseline.txt`, "Error reading valid buildinfo file");
|
||||
generateBuildInfoProgramBaseline(sys, buildInfoPath, buildInfo);
|
||||
|
||||
if (!ts.outFile(options)) return;
|
||||
const { jsFilePath, declarationFilePath } = ts.getOutputPathsForBundle(options, /*forceDts*/ false);
|
||||
const bundle = buildInfo.bundle;
|
||||
if (!bundle || (!ts.length(bundle.js && bundle.js.sections) && !ts.length(bundle.dts && bundle.dts.sections))) return;
|
||||
|
||||
// Write the baselines:
|
||||
const baselineRecorder = new Harness.Compiler.WriterAggregator();
|
||||
generateBundleFileSectionInfo(sys, originalReadCall || sys.readFile, baselineRecorder, bundle.js, jsFilePath);
|
||||
generateBundleFileSectionInfo(sys, originalReadCall || sys.readFile, baselineRecorder, bundle.dts, declarationFilePath);
|
||||
baselineRecorder.Close();
|
||||
const text = baselineRecorder.lines.join("\r\n");
|
||||
sys.writeFile(`${buildInfoPath}.baseline.txt`, text);
|
||||
}
|
||||
interface VerifyTscEditDiscrepanciesInput {
|
||||
index: number;
|
||||
scenario: ts.TestTscCompile["scenario"];
|
||||
subScenario: ts.TestTscCompile["subScenario"];
|
||||
baselines: string[] | undefined;
|
||||
commandLineArgs: ts.TestTscCompile["commandLineArgs"];
|
||||
modifyFs: ts.TestTscCompile["modifyFs"];
|
||||
editFs: TestTscEdit["modifyFs"];
|
||||
baseFs: vfs.FileSystem;
|
||||
newSys: ts.TscCompileSystem;
|
||||
discrepancyExplanation: TestTscEdit["discrepancyExplanation"];
|
||||
}
|
||||
function verifyTscEditDiscrepancies({
|
||||
index, scenario, subScenario, commandLineArgs,
|
||||
discrepancyExplanation, baselines,
|
||||
modifyFs, editFs, baseFs, newSys
|
||||
}: VerifyTscEditDiscrepanciesInput): string[] | undefined {
|
||||
const sys = ts.testTscCompile({
|
||||
scenario,
|
||||
subScenario,
|
||||
fs: () => baseFs.makeReadonly(),
|
||||
commandLineArgs,
|
||||
modifyFs: fs => {
|
||||
if (modifyFs) modifyFs(fs);
|
||||
editFs(fs);
|
||||
},
|
||||
disableUseFileVersionAsSignature: true,
|
||||
});
|
||||
let headerAdded = false;
|
||||
for (const outputFile of ts.arrayFrom(sys.writtenFiles.keys())) {
|
||||
const cleanBuildText = sys.readFile(outputFile);
|
||||
const incrementalBuildText = newSys.readFile(outputFile);
|
||||
if (ts.isBuildInfoFile(outputFile)) {
|
||||
// Check only presence and absence and not text as we will do that for readable baseline
|
||||
if (!sys.fileExists(`${outputFile}.readable.baseline.txt`)) addBaseline(`Readable baseline not present in clean build:: File:: ${outputFile}`);
|
||||
if (!newSys.fileExists(`${outputFile}.readable.baseline.txt`)) addBaseline(`Readable baseline not present in incremental build:: File:: ${outputFile}`);
|
||||
verifyPresenceAbsence(incrementalBuildText, cleanBuildText, `Incremental and clean tsbuildinfo file presence differs:: File:: ${outputFile}`);
|
||||
}
|
||||
else if (!ts.fileExtensionIs(outputFile, ".tsbuildinfo.readable.baseline.txt")) {
|
||||
verifyTextEqual(incrementalBuildText, cleanBuildText, `File: ${outputFile}`);
|
||||
}
|
||||
else if (incrementalBuildText !== cleanBuildText) {
|
||||
// Verify build info without affectedFilesPendingEmit
|
||||
const { buildInfo: incrementalBuildInfo, readableBuildInfo: incrementalReadableBuildInfo } = getBuildInfoForIncrementalCorrectnessCheck(incrementalBuildText);
|
||||
const { buildInfo: cleanBuildInfo, readableBuildInfo: cleanReadableBuildInfo } = getBuildInfoForIncrementalCorrectnessCheck(cleanBuildText);
|
||||
verifyTextEqual(incrementalBuildInfo, cleanBuildInfo, `TsBuild info text without affectedFilesPendingEmit:: ${outputFile}::`);
|
||||
// Verify file info sigantures
|
||||
verifyMapLike(
|
||||
incrementalReadableBuildInfo?.program?.fileInfos as ReadableProgramMultiFileEmitBuildInfo["fileInfos"],
|
||||
cleanReadableBuildInfo?.program?.fileInfos as ReadableProgramMultiFileEmitBuildInfo["fileInfos"],
|
||||
(key, incrementalFileInfo, cleanFileInfo) => {
|
||||
if (incrementalFileInfo.signature !== cleanFileInfo.signature && incrementalFileInfo.signature !== incrementalFileInfo.version) {
|
||||
return [
|
||||
`Incremental signature is neither dts signature nor file version for File:: ${key}`,
|
||||
`Incremental:: ${JSON.stringify(incrementalFileInfo, /*replacer*/ undefined, 2)}`,
|
||||
`Clean:: ${JSON.stringify(cleanFileInfo, /*replacer*/ undefined, 2)}`
|
||||
];
|
||||
}
|
||||
},
|
||||
`FileInfos:: File:: ${outputFile}`
|
||||
);
|
||||
if (!isReadableProgramBundleEmitBuildInfo(incrementalReadableBuildInfo?.program)) {
|
||||
ts.Debug.assert(!isReadableProgramBundleEmitBuildInfo(cleanReadableBuildInfo?.program));
|
||||
// Verify exportedModulesMap
|
||||
verifyMapLike(
|
||||
incrementalReadableBuildInfo?.program?.exportedModulesMap,
|
||||
cleanReadableBuildInfo?.program?.exportedModulesMap,
|
||||
(key, incrementalReferenceSet, cleanReferenceSet) => {
|
||||
if (!ts.arrayIsEqualTo(incrementalReferenceSet, cleanReferenceSet) && !ts.arrayIsEqualTo(incrementalReferenceSet, (incrementalReadableBuildInfo!.program! as ReadableProgramMultiFileEmitBuildInfo).referencedMap![key])) {
|
||||
return [
|
||||
`Incremental Reference set is neither from dts nor files reference map for File:: ${key}::`,
|
||||
`Incremental:: ${JSON.stringify(incrementalReferenceSet, /*replacer*/ undefined, 2)}`,
|
||||
`Clean:: ${JSON.stringify(cleanReferenceSet, /*replacer*/ undefined, 2)}`,
|
||||
`IncrementalReferenceMap:: ${JSON.stringify((incrementalReadableBuildInfo!.program! as ReadableProgramMultiFileEmitBuildInfo).referencedMap![key], /*replacer*/ undefined, 2)}`,
|
||||
`CleanReferenceMap:: ${JSON.stringify((cleanReadableBuildInfo!.program! as ReadableProgramMultiFileEmitBuildInfo).referencedMap![key], /*replacer*/ undefined, 2)}`,
|
||||
];
|
||||
}
|
||||
},
|
||||
`exportedModulesMap:: File:: ${outputFile}`
|
||||
);
|
||||
// Verify that incrementally pending affected file emit are in clean build since clean build can contain more files compared to incremental depending of noEmitOnError option
|
||||
if (incrementalReadableBuildInfo?.program?.affectedFilesPendingEmit) {
|
||||
if (cleanReadableBuildInfo?.program?.affectedFilesPendingEmit === undefined) {
|
||||
addBaseline(
|
||||
`Incremental build contains affectedFilesPendingEmit, clean build does not have it: ${outputFile}::`,
|
||||
`Incremental buildInfoText:: ${incrementalBuildText}`,
|
||||
`Clean buildInfoText:: ${cleanBuildText}`
|
||||
);
|
||||
}
|
||||
let expectedIndex = 0;
|
||||
incrementalReadableBuildInfo.program.affectedFilesPendingEmit.forEach(([actualFileOrArray]) => {
|
||||
const actualFile = ts.isString(actualFileOrArray) ? actualFileOrArray : actualFileOrArray[0];
|
||||
expectedIndex = ts.findIndex(
|
||||
(cleanReadableBuildInfo!.program! as ReadableProgramMultiFileEmitBuildInfo).affectedFilesPendingEmit,
|
||||
([expectedFileOrArray]) => actualFile === (ts.isString(expectedFileOrArray) ? expectedFileOrArray : expectedFileOrArray[0]),
|
||||
expectedIndex
|
||||
);
|
||||
if (expectedIndex === -1) {
|
||||
addBaseline(
|
||||
`Incremental build contains ${actualFile} file as pending emit, clean build does not have it: ${outputFile}::`,
|
||||
`Incremental buildInfoText:: ${incrementalBuildText}`,
|
||||
`Clean buildInfoText:: ${cleanBuildText}`
|
||||
);
|
||||
}
|
||||
expectedIndex++;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!headerAdded && discrepancyExplanation) addBaseline("*** Supplied discrepancy explanation but didnt file any difference");
|
||||
return baselines;
|
||||
|
||||
function verifyTextEqual(incrementalText: string | undefined, cleanText: string | undefined, message: string) {
|
||||
if (incrementalText !== cleanText) writeNotEqual(incrementalText, cleanText, message);
|
||||
}
|
||||
|
||||
function verifyMapLike<T>(incremental: ts.MapLike<T> | undefined, clean: ts.MapLike<T> | undefined, verifyValue: (key: string, incrementalValue: T, cleanValue: T) => string[] | undefined, message: string) {
|
||||
verifyPresenceAbsence(incremental, clean, `Incremental and clean do not match:: ${message}`);
|
||||
if (!incremental || !clean) return;
|
||||
const incrementalMap = new ts.Map(ts.getEntries(incremental));
|
||||
const cleanMap = new ts.Map(ts.getEntries(clean));
|
||||
if (incrementalMap.size !== cleanMap.size) {
|
||||
addBaseline(
|
||||
`Incremental and clean size of maps do not match:: ${message}`,
|
||||
`Incremental: ${JSON.stringify(incremental, /*replacer*/ undefined, 2)}`,
|
||||
`Clean: ${JSON.stringify(clean, /*replacer*/ undefined, 2)}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
cleanMap.forEach((cleanValue, key) => {
|
||||
const incrementalValue = incrementalMap.get(key);
|
||||
if (!incrementalValue) {
|
||||
addBaseline(
|
||||
`Incremental does not contain ${key} which is present in clean:: ${message}`,
|
||||
`Incremental: ${JSON.stringify(incremental, /*replacer*/ undefined, 2)}`,
|
||||
`Clean: ${JSON.stringify(clean, /*replacer*/ undefined, 2)}`,
|
||||
);
|
||||
}
|
||||
else {
|
||||
const result = verifyValue(key, incrementalMap.get(key)!, cleanValue);
|
||||
if (result) addBaseline(...result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function verifyPresenceAbsence<T>(actual: T | undefined, expected: T | undefined, message: string) {
|
||||
if (expected === undefined) {
|
||||
if (actual === undefined) return;
|
||||
}
|
||||
else {
|
||||
if (actual !== undefined) return;
|
||||
}
|
||||
writeNotEqual(actual, expected, message);
|
||||
}
|
||||
|
||||
function writeNotEqual<T>(actual: T | undefined, expected: T | undefined, message: string) {
|
||||
addBaseline(
|
||||
message,
|
||||
"CleanBuild:",
|
||||
ts.isString(expected) ? expected : JSON.stringify(expected),
|
||||
"IncrementalBuild:",
|
||||
ts.isString(actual) ? actual : JSON.stringify(actual),
|
||||
);
|
||||
}
|
||||
|
||||
function addBaseline(...text: string[]) {
|
||||
if (!baselines || !headerAdded) {
|
||||
(baselines ||= []).push(`${index}:: ${subScenario}`, ...(discrepancyExplanation?.()|| ["*** Needs explanation"]));
|
||||
headerAdded = true;
|
||||
}
|
||||
baselines.push(...text);
|
||||
}
|
||||
}
|
||||
|
||||
function getBuildInfoForIncrementalCorrectnessCheck(text: string | undefined): {
|
||||
buildInfo: string | undefined;
|
||||
readableBuildInfo?: ReadableBuildInfo;
|
||||
} {
|
||||
if (!text) return { buildInfo: text };
|
||||
const readableBuildInfo = JSON.parse(text) as ReadableBuildInfo;
|
||||
let sanitizedFileInfos: ts.MapLike<string | Omit<ReadableProgramBuildInfoFileInfo<ts.ProgramMultiFileEmitBuildInfoFileInfo> | ReadableProgramBuildInfoFileInfo<ts.BuilderState.FileInfo>, "signature" | "original"> & { signature: undefined; original: undefined; }> | undefined;
|
||||
if (readableBuildInfo.program?.fileInfos) {
|
||||
sanitizedFileInfos = {};
|
||||
for (const id in readableBuildInfo.program.fileInfos) {
|
||||
if (ts.hasProperty(readableBuildInfo.program.fileInfos, id)) {
|
||||
const info = readableBuildInfo.program.fileInfos[id];
|
||||
sanitizedFileInfos[id] = ts.isString(info) ? info : { ...info, signature: undefined, original: undefined };
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
buildInfo: JSON.stringify({
|
||||
...readableBuildInfo,
|
||||
program: readableBuildInfo.program && {
|
||||
...readableBuildInfo.program,
|
||||
fileNames: undefined,
|
||||
fileNamesList: undefined,
|
||||
fileInfos: sanitizedFileInfos,
|
||||
// Ignore noEmit since that shouldnt be reason to emit the tsbuild info and presence of it in the buildinfo file does not matter
|
||||
options: { ...readableBuildInfo.program.options, noEmit: undefined },
|
||||
exportedModulesMap: undefined,
|
||||
affectedFilesPendingEmit: undefined,
|
||||
latestChangedDtsFile: readableBuildInfo.program.latestChangedDtsFile ? "FakeFileName" : undefined,
|
||||
},
|
||||
size: undefined, // Size doesnt need to be equal
|
||||
}, /*replacer*/ undefined, 2),
|
||||
readableBuildInfo,
|
||||
};
|
||||
}
|
||||
|
||||
export enum CleanBuildDescrepancy {
|
||||
CleanFileTextDifferent,
|
||||
CleanFilePresent,
|
||||
}
|
||||
|
||||
export interface TestTscEdit {
|
||||
modifyFs: (fs: vfs.FileSystem) => void;
|
||||
subScenario: string;
|
||||
commandLineArgs?: readonly string[];
|
||||
/** An array of lines to be printed in order when a discrepancy is detected */
|
||||
discrepancyExplanation?: () => readonly string[];
|
||||
}
|
||||
|
||||
export interface VerifyTscWithEditsInput extends ts.TestTscCompile {
|
||||
edits: TestTscEdit[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify non watch tsc invokcation after each edit
|
||||
*/
|
||||
export function verifyTscWithEdits({
|
||||
subScenario, fs, scenario, commandLineArgs,
|
||||
baselineSourceMap, modifyFs, baselineReadFileCalls, baselinePrograms,
|
||||
edits
|
||||
}: VerifyTscWithEditsInput) {
|
||||
describe(`tsc ${commandLineArgs.join(" ")} ${scenario}:: ${subScenario} serializedEdits`, () => {
|
||||
let sys: ts.TscCompileSystem;
|
||||
let baseFs: vfs.FileSystem;
|
||||
let editsSys: ts.TscCompileSystem[];
|
||||
before(() => {
|
||||
ts.Debug.assert(!!edits.length, `${scenario}/${subScenario}:: No incremental scenarios, you probably want to use verifyTsc instead.`);
|
||||
baseFs = fs().makeReadonly();
|
||||
sys = ts.testTscCompile({
|
||||
scenario,
|
||||
subScenario,
|
||||
fs: () => baseFs,
|
||||
commandLineArgs,
|
||||
modifyFs,
|
||||
baselineSourceMap,
|
||||
baselineReadFileCalls,
|
||||
baselinePrograms
|
||||
});
|
||||
edits.forEach((
|
||||
{ modifyFs, subScenario: editScenario, commandLineArgs: editCommandLineArgs },
|
||||
index
|
||||
) => {
|
||||
(editsSys || (editsSys = [])).push(ts.testTscCompile({
|
||||
scenario,
|
||||
subScenario: editScenario || subScenario,
|
||||
diffWithInitial: true,
|
||||
fs: () => index === 0 ? sys.vfs : editsSys[index - 1].vfs,
|
||||
commandLineArgs: editCommandLineArgs || commandLineArgs,
|
||||
modifyFs,
|
||||
baselineSourceMap,
|
||||
baselineReadFileCalls,
|
||||
baselinePrograms
|
||||
}));
|
||||
});
|
||||
});
|
||||
after(() => {
|
||||
baseFs = undefined!;
|
||||
sys = undefined!;
|
||||
editsSys = undefined!;
|
||||
});
|
||||
ts.verifyTscBaseline(() => ({
|
||||
baseLine: () => {
|
||||
const { file, text } = sys.baseLine();
|
||||
const texts: string[] = [text];
|
||||
editsSys.forEach((sys, index) => {
|
||||
const incrementalScenario = edits[index];
|
||||
texts.push("");
|
||||
texts.push(`Change:: ${incrementalScenario.subScenario}`);
|
||||
texts.push(sys.baseLine().text);
|
||||
});
|
||||
return { file, text: texts.join("\r\n") };
|
||||
}
|
||||
}));
|
||||
it("tsc invocation after edit and clean build correctness", () => {
|
||||
let baselines: string[] | undefined;
|
||||
for (let index = 0; index < edits.length; index++) {
|
||||
baselines = verifyTscEditDiscrepancies({
|
||||
index,
|
||||
scenario,
|
||||
subScenario: edits[index].subScenario,
|
||||
baselines,
|
||||
baseFs,
|
||||
newSys: editsSys[index],
|
||||
commandLineArgs: edits[index].commandLineArgs || commandLineArgs,
|
||||
discrepancyExplanation: edits[index].discrepancyExplanation,
|
||||
editFs: fs => {
|
||||
for (let i = 0; i <= index; i++) {
|
||||
edits[i].modifyFs(fs);
|
||||
}
|
||||
},
|
||||
modifyFs
|
||||
});
|
||||
}
|
||||
Harness.Baseline.runBaseline(
|
||||
`${ts.isBuild(commandLineArgs) ? "tsbuild" : "tsc"}/${scenario}/${subScenario.split(" ").join("-")}-discrepancies.js`,
|
||||
baselines ? baselines.join("\r\n") : null // eslint-disable-line no-null/no-null
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function enableStrict(fs: vfs.FileSystem, path: string) {
|
||||
replaceText(fs, path, `"strict": false`, `"strict": true`);
|
||||
}
|
||||
|
||||
export function addTestPrologue(fs: vfs.FileSystem, path: string, prologue: string) {
|
||||
prependText(fs, path, `${prologue}
|
||||
`);
|
||||
}
|
||||
|
||||
export function addShebang(fs: vfs.FileSystem, project: string, file: string) {
|
||||
prependText(fs, `src/${project}/${file}.ts`, `#!someshebang ${project} ${file}
|
||||
`);
|
||||
}
|
||||
|
||||
export function restContent(project: string, file: string) {
|
||||
return `function for${project}${file}Rest() {
|
||||
const { b, ...rest } = { a: 10, b: 30, yy: 30 };
|
||||
}`;
|
||||
}
|
||||
|
||||
function nonrestContent(project: string, file: string) {
|
||||
return `function for${project}${file}Rest() { }`;
|
||||
}
|
||||
|
||||
export function addRest(fs: vfs.FileSystem, project: string, file: string) {
|
||||
appendText(fs, `src/${project}/${file}.ts`, restContent(project, file));
|
||||
}
|
||||
|
||||
export function removeRest(fs: vfs.FileSystem, project: string, file: string) {
|
||||
replaceText(fs, `src/${project}/${file}.ts`, restContent(project, file), nonrestContent(project, file));
|
||||
}
|
||||
|
||||
export function addStubFoo(fs: vfs.FileSystem, project: string, file: string) {
|
||||
appendText(fs, `src/${project}/${file}.ts`, nonrestContent(project, file));
|
||||
}
|
||||
|
||||
export function changeStubToRest(fs: vfs.FileSystem, project: string, file: string) {
|
||||
replaceText(fs, `src/${project}/${file}.ts`, nonrestContent(project, file), restContent(project, file));
|
||||
}
|
||||
|
||||
export function addSpread(fs: vfs.FileSystem, project: string, file: string) {
|
||||
const path = `src/${project}/${file}.ts`;
|
||||
const content = fs.readFileSync(path, "utf8");
|
||||
fs.writeFileSync(path, `${content}
|
||||
function ${project}${file}Spread(...b: number[]) { }
|
||||
const ${project}${file}_ar = [20, 30];
|
||||
${project}${file}Spread(10, ...${project}${file}_ar);`);
|
||||
|
||||
replaceText(fs, `src/${project}/tsconfig.json`, `"strict": false,`, `"strict": false,
|
||||
"downlevelIteration": true,`);
|
||||
}
|
||||
|
||||
export function getTripleSlashRef(project: string) {
|
||||
return `/src/${project}/tripleRef.d.ts`;
|
||||
}
|
||||
|
||||
export function addTripleSlashRef(fs: vfs.FileSystem, project: string, file: string) {
|
||||
fs.writeFileSync(getTripleSlashRef(project), `declare class ${project}${file} { }`);
|
||||
prependText(fs, `src/${project}/${file}.ts`, `///<reference path="./tripleRef.d.ts"/>
|
||||
const ${file}Const = new ${project}${file}();
|
||||
`);
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as vfs from "../../_namespaces/vfs";
|
||||
import { appendText, loadProjectFromDisk, replaceText, verifyTscWithEdits } from "../tsc/helpers";
|
||||
|
||||
describe("unittests:: tsbuild:: inferredTypeFromTransitiveModule::", () => {
|
||||
let projFs: vfs.FileSystem;
|
||||
before(() => {
|
||||
projFs = ts.loadProjectFromDisk("tests/projects/inferredTypeFromTransitiveModule");
|
||||
projFs = loadProjectFromDisk("tests/projects/inferredTypeFromTransitiveModule");
|
||||
});
|
||||
after(() => {
|
||||
projFs = undefined!;
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "inferredTypeFromTransitiveModule",
|
||||
subScenario: "inferred type from transitive module",
|
||||
fs: () => projFs,
|
||||
@@ -27,7 +27,7 @@ describe("unittests:: tsbuild:: inferredTypeFromTransitiveModule::", () => {
|
||||
],
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
subScenario: "inferred type from transitive module with isolatedModules",
|
||||
fs: () => projFs,
|
||||
scenario: "inferredTypeFromTransitiveModule",
|
||||
@@ -45,14 +45,14 @@ describe("unittests:: tsbuild:: inferredTypeFromTransitiveModule::", () => {
|
||||
]
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "inferredTypeFromTransitiveModule",
|
||||
subScenario: "reports errors in files affected by change in signature with isolatedModules",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "/src", "--verbose"],
|
||||
modifyFs: fs => {
|
||||
changeToIsolatedModules(fs);
|
||||
ts.appendText(fs, "/src/lazyIndex.ts", `
|
||||
appendText(fs, "/src/lazyIndex.ts", `
|
||||
import { default as bar } from './bar';
|
||||
bar("hello");`);
|
||||
},
|
||||
@@ -71,20 +71,20 @@ bar("hello");`);
|
||||
},
|
||||
{
|
||||
subScenario: "Fix Error",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/lazyIndex.ts", `bar("hello")`, "bar()")
|
||||
modifyFs: fs => replaceText(fs, "/src/lazyIndex.ts", `bar("hello")`, "bar()")
|
||||
},
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
function changeToIsolatedModules(fs: vfs.FileSystem) {
|
||||
ts.replaceText(fs, "/src/tsconfig.json", `"incremental": true`, `"incremental": true, "isolatedModules": true`);
|
||||
replaceText(fs, "/src/tsconfig.json", `"incremental": true`, `"incremental": true, "isolatedModules": true`);
|
||||
}
|
||||
|
||||
function changeBarParam(fs: vfs.FileSystem) {
|
||||
ts.replaceText(fs, "/src/bar.ts", "param: string", "");
|
||||
replaceText(fs, "/src/bar.ts", "param: string", "");
|
||||
}
|
||||
|
||||
function changeBarParamBack(fs: vfs.FileSystem) {
|
||||
ts.replaceText(fs, "/src/bar.ts", "foobar()", "foobar(param: string)");
|
||||
replaceText(fs, "/src/bar.ts", "foobar()", "foobar(param: string)");
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as Utils from "../../_namespaces/Utils";
|
||||
import { loadProjectFromFiles, replaceText, symbolLibContent, verifyTsc, verifyTscWithEdits } from "../tsc/helpers";
|
||||
|
||||
describe("unittests:: tsbuild:: javascriptProjectEmit::", () => {
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "javascriptProjectEmit",
|
||||
subScenario: `loads js-based projects and emits them correctly`,
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/common/nominal.js": Utils.dedent`
|
||||
/**
|
||||
* @template T, Name
|
||||
@@ -86,14 +86,14 @@ describe("unittests:: tsbuild:: javascriptProjectEmit::", () => {
|
||||
"declaration": true
|
||||
}
|
||||
}`,
|
||||
}, ts.symbolLibContent),
|
||||
}, symbolLibContent),
|
||||
commandLineArgs: ["-b", "/src"]
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "javascriptProjectEmit",
|
||||
subScenario: `modifies outfile js projects and concatenates them correctly`,
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/common/nominal.js": Utils.dedent`
|
||||
/**
|
||||
* @template T, Name
|
||||
@@ -176,18 +176,18 @@ describe("unittests:: tsbuild:: javascriptProjectEmit::", () => {
|
||||
"declaration": true
|
||||
}
|
||||
}`,
|
||||
}, ts.symbolLibContent),
|
||||
}, symbolLibContent),
|
||||
commandLineArgs: ["-b", "/src"],
|
||||
edits: [{
|
||||
subScenario: "incremental-declaration-doesnt-change",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/sub-project/index.js", "null", "undefined")
|
||||
modifyFs: fs => replaceText(fs, "/src/sub-project/index.js", "null", "undefined")
|
||||
}]
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "javascriptProjectEmit",
|
||||
subScenario: `loads js-based projects with non-moved json files and emits them correctly`,
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/common/obj.json": Utils.dedent`
|
||||
{
|
||||
"val": 42
|
||||
@@ -267,7 +267,7 @@ describe("unittests:: tsbuild:: javascriptProjectEmit::", () => {
|
||||
"declaration": true
|
||||
}
|
||||
}`,
|
||||
}, ts.symbolLibContent),
|
||||
}, symbolLibContent),
|
||||
commandLineArgs: ["-b", "/src"]
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { replaceText, appendText, loadProjectFromDisk, verifyTscWithEdits } from "../tsc/helpers";
|
||||
|
||||
describe("unittests:: tsbuild:: lateBoundSymbol:: interface is merged and contains late bound member", () => {
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
subScenario: "interface is merged and contains late bound member",
|
||||
fs: () => ts.loadProjectFromDisk("tests/projects/lateBoundSymbol"),
|
||||
fs: () => loadProjectFromDisk("tests/projects/lateBoundSymbol"),
|
||||
scenario: "lateBoundSymbol",
|
||||
commandLineArgs: ["--b", "/src/tsconfig.json", "--verbose"],
|
||||
edits: [
|
||||
{
|
||||
subScenario: "incremental-declaration-doesnt-change",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/src/main.ts", "const x = 10;", ""),
|
||||
modifyFs: fs => replaceText(fs, "/src/src/main.ts", "const x = 10;", ""),
|
||||
},
|
||||
{
|
||||
subScenario: "incremental-declaration-doesnt-change",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/src/main.ts", "const x = 10;"),
|
||||
modifyFs: fs => appendText(fs, "/src/src/main.ts", "const x = 10;"),
|
||||
},
|
||||
]
|
||||
});
|
||||
|
||||
@@ -1,32 +1,35 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as Utils from "../../_namespaces/Utils";
|
||||
import { createWatchedSystem, libFile } from "../virtualFileSystemWithWatch";
|
||||
import { loadProjectFromFiles, noChangeOnlyRuns, verifyTsc, verifyTscWithEdits } from "../tsc/helpers";
|
||||
import { verifyTscWatch } from "../tscWatch/helpers";
|
||||
|
||||
describe("unittests:: tsbuild:: moduleResolution:: handles the modules and options from referenced project correctly", () => {
|
||||
function sys(optionsToExtend?: ts.CompilerOptions) {
|
||||
return ts.tscWatch.createWatchedSystem([
|
||||
return createWatchedSystem([
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/packages/pkg1/index.ts`,
|
||||
path: `/user/username/projects/myproject/packages/pkg1/index.ts`,
|
||||
content: Utils.dedent`
|
||||
import type { TheNum } from 'pkg2'
|
||||
export const theNum: TheNum = 42;`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/packages/pkg1/tsconfig.json`,
|
||||
path: `/user/username/projects/myproject/packages/pkg1/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { outDir: "build", ...optionsToExtend },
|
||||
references: [{ path: "../pkg2" }]
|
||||
})
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/packages/pkg2/const.ts`,
|
||||
path: `/user/username/projects/myproject/packages/pkg2/const.ts`,
|
||||
content: `export type TheNum = 42;`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/packages/pkg2/index.ts`,
|
||||
path: `/user/username/projects/myproject/packages/pkg2/index.ts`,
|
||||
content: `export type { TheNum } from 'const';`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/packages/pkg2/tsconfig.json`,
|
||||
path: `/user/username/projects/myproject/packages/pkg2/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
composite: true,
|
||||
@@ -37,7 +40,7 @@ describe("unittests:: tsbuild:: moduleResolution:: handles the modules and optio
|
||||
})
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/packages/pkg2/package.json`,
|
||||
path: `/user/username/projects/myproject/packages/pkg2/package.json`,
|
||||
content: JSON.stringify({
|
||||
name: "pkg2",
|
||||
version: "1.0.0",
|
||||
@@ -45,14 +48,14 @@ describe("unittests:: tsbuild:: moduleResolution:: handles the modules and optio
|
||||
})
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/pkg2`,
|
||||
symLink: `${ts.tscWatch.projectRoot}/packages/pkg2`,
|
||||
path: `/user/username/projects/myproject/node_modules/pkg2`,
|
||||
symLink: `/user/username/projects/myproject/packages/pkg2`,
|
||||
},
|
||||
ts.tscWatch.libFile
|
||||
], { currentDirectory: ts.tscWatch.projectRoot });
|
||||
libFile
|
||||
], { currentDirectory: "/user/username/projects/myproject" });
|
||||
}
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "moduleResolution",
|
||||
subScenario: `resolves specifier in output declaration file from referenced project correctly`,
|
||||
sys,
|
||||
@@ -60,7 +63,7 @@ describe("unittests:: tsbuild:: moduleResolution:: handles the modules and optio
|
||||
changes: ts.emptyArray
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "moduleResolution",
|
||||
subScenario: `resolves specifier in output declaration file from referenced project correctly with preserveSymlinks`,
|
||||
sys: () => sys({ preserveSymlinks: true }),
|
||||
@@ -68,10 +71,10 @@ describe("unittests:: tsbuild:: moduleResolution:: handles the modules and optio
|
||||
changes: ts.emptyArray
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "moduleResolution",
|
||||
subScenario: `type reference resolution uses correct options for different resolution options referenced project`,
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/packages/pkg1_index.ts": `export const theNum: TheNum = "type1";`,
|
||||
"/src/packages/pkg1.tsconfig.json": JSON.stringify({
|
||||
compilerOptions: { composite: true, typeRoots: ["./typeroot1"] },
|
||||
@@ -90,10 +93,10 @@ describe("unittests:: tsbuild:: moduleResolution:: handles the modules and optio
|
||||
});
|
||||
|
||||
describe("unittests:: tsbuild:: moduleResolution:: impliedNodeFormat differs between projects for shared file", () => {
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "moduleResolution",
|
||||
subScenario: "impliedNodeFormat differs between projects for shared file",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/projects/a/src/index.ts": "",
|
||||
"/src/projects/a/tsconfig.json": JSON.stringify({
|
||||
compilerOptions: { strict: true }
|
||||
@@ -115,8 +118,8 @@ describe("unittests:: tsbuild:: moduleResolution:: impliedNodeFormat differs bet
|
||||
types: "index.d.ts",
|
||||
}),
|
||||
}),
|
||||
modifyFs: fs => fs.writeFileSync("/lib/lib.es2022.full.d.ts", ts.tscWatch.libFile.content),
|
||||
modifyFs: fs => fs.writeFileSync("/lib/lib.es2022.full.d.ts", libFile.content),
|
||||
commandLineArgs: ["-b", "/src/projects/a", "/src/projects/b", "--verbose", "--traceResolution", "--explainFiles"],
|
||||
edits: ts.noChangeOnlyRuns
|
||||
edits: noChangeOnlyRuns
|
||||
});
|
||||
});
|
||||
@@ -1,12 +1,13 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { libFile } from "../virtualFileSystemWithWatch";
|
||||
import * as Utils from "../../_namespaces/Utils";
|
||||
import { loadProjectFromFiles, symbolLibContent, verifyTsc } from "../tsc/helpers";
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/31696
|
||||
describe("unittests:: tsbuild:: moduleSpecifiers:: synthesized module specifiers to referenced projects resolve correctly", () => {
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "moduleSpecifiers",
|
||||
subScenario: `synthesized module specifiers resolve correctly`,
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/solution/common/nominal.ts": Utils.dedent`
|
||||
export declare type Nominal<T, Name extends string> = T & {
|
||||
[Symbol.species]: Name;
|
||||
@@ -86,17 +87,17 @@ describe("unittests:: tsbuild:: moduleSpecifiers:: synthesized module specifiers
|
||||
],
|
||||
"include": []
|
||||
}`
|
||||
}, ts.symbolLibContent),
|
||||
}, symbolLibContent),
|
||||
commandLineArgs: ["-b", "/src", "--verbose"]
|
||||
});
|
||||
});
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/44434 but with `module: node16`, some `exports` maps blocking direct access, and no `baseUrl`
|
||||
describe("unittests:: tsbuild:: moduleSpecifiers:: synthesized module specifiers across referenced projects resolve correctly", () => {
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "moduleSpecifiers",
|
||||
subScenario: `synthesized module specifiers across projects resolve correctly`,
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/src-types/index.ts": Utils.dedent`
|
||||
export * from './dogconfig.js';`,
|
||||
"/src/src-types/dogconfig.ts": Utils.dedent`
|
||||
@@ -180,7 +181,7 @@ describe("unittests:: tsbuild:: moduleSpecifiers:: synthesized module specifiers
|
||||
}`,
|
||||
}, ""),
|
||||
modifyFs: fs => {
|
||||
fs.writeFileSync("/lib/lib.es2022.full.d.ts", ts.tscWatch.libFile.content);
|
||||
fs.writeFileSync("/lib/lib.es2022.full.d.ts", libFile.content);
|
||||
fs.symlinkSync("/src", "/src/src-types/node_modules");
|
||||
fs.symlinkSync("/src", "/src/src-dogs/node_modules");
|
||||
},
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { loadProjectFromFiles, noChangeRun, verifyTscWithEdits } from "../tsc/helpers";
|
||||
|
||||
describe("unittests:: tsbuild:: noEmit", () => {
|
||||
function verifyNoEmitWorker(subScenario: string, aTsContent: string, commandLineArgs: readonly string[]) {
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "noEmit",
|
||||
subScenario,
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/a.ts": aTsContent,
|
||||
"/src/tsconfig.json": JSON.stringify({
|
||||
compilerOptions: { noEmit: true }
|
||||
@@ -13,12 +13,12 @@ describe("unittests:: tsbuild:: noEmit", () => {
|
||||
}),
|
||||
commandLineArgs,
|
||||
edits: [
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
{
|
||||
subScenario: "Fix error",
|
||||
modifyFs: fs => fs.writeFileSync("/src/a.ts", `const a = "hello"`),
|
||||
},
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
],
|
||||
baselinePrograms: true,
|
||||
});
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { loadProjectFromDisk, noChangeRun, noChangeWithExportsDiscrepancyRun, verifyTscWithEdits } from "../tsc/helpers";
|
||||
import * as vfs from "../../_namespaces/vfs";
|
||||
|
||||
describe("unittests:: tsbuild - with noEmitOnError", () => {
|
||||
let projFs: vfs.FileSystem;
|
||||
before(() => {
|
||||
projFs = ts.loadProjectFromDisk("tests/projects/noEmitOnError");
|
||||
projFs = loadProjectFromDisk("tests/projects/noEmitOnError");
|
||||
});
|
||||
after(() => {
|
||||
projFs = undefined!;
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "noEmitOnError",
|
||||
subScenario: "syntax errors",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "/src/tsconfig.json"],
|
||||
edits: [
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
{
|
||||
subScenario: "Fix error",
|
||||
modifyFs: fs => fs.writeFileSync("/src/src/main.ts", `import { A } from "../shared/types/db";
|
||||
@@ -24,18 +24,18 @@ const a = {
|
||||
lastName: 'sdsd'
|
||||
};`, "utf-8"),
|
||||
},
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
],
|
||||
baselinePrograms: true,
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "noEmitOnError",
|
||||
subScenario: "syntax errors with incremental",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "/src/tsconfig.json", "--incremental"],
|
||||
edits: [
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
{
|
||||
subScenario: "Fix error",
|
||||
modifyFs: fs => fs.writeFileSync("/src/src/main.ts", `import { A } from "../shared/types/db";
|
||||
@@ -43,12 +43,12 @@ const a = {
|
||||
lastName: 'sdsd'
|
||||
};`, "utf-8"),
|
||||
},
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
],
|
||||
baselinePrograms: true,
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "noEmitOnError",
|
||||
subScenario: "semantic errors",
|
||||
fs: () => projFs,
|
||||
@@ -56,18 +56,18 @@ const a = {
|
||||
const a: string = 10;`, "utf-8"),
|
||||
commandLineArgs: ["--b", "/src/tsconfig.json"],
|
||||
edits: [
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
{
|
||||
subScenario: "Fix error",
|
||||
modifyFs: fs => fs.writeFileSync("/src/src/main.ts", `import { A } from "../shared/types/db";
|
||||
const a: string = "hello";`, "utf-8"),
|
||||
},
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
],
|
||||
baselinePrograms: true,
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "noEmitOnError",
|
||||
subScenario: "semantic errors with incremental",
|
||||
fs: () => projFs,
|
||||
@@ -75,13 +75,13 @@ const a: string = "hello";`, "utf-8"),
|
||||
const a: string = 10;`, "utf-8"),
|
||||
commandLineArgs: ["--b", "/src/tsconfig.json", "--incremental"],
|
||||
edits: [
|
||||
ts.noChangeWithExportsDiscrepancyRun,
|
||||
noChangeWithExportsDiscrepancyRun,
|
||||
{
|
||||
subScenario: "Fix error",
|
||||
modifyFs: fs => fs.writeFileSync("/src/src/main.ts", `import { A } from "../shared/types/db";
|
||||
const a: string = "hello";`, "utf-8"),
|
||||
},
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
],
|
||||
baselinePrograms: true,
|
||||
});
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as vfs from "../../_namespaces/vfs";
|
||||
import * as fakes from "../../_namespaces/fakes";
|
||||
import { addRest, addShebang, addSpread, addStubFoo, addTestPrologue, addTripleSlashRef, appendText, changeStubToRest, createSolutionBuilderHostForBaseline, enableStrict, loadProjectFromDisk, noChangeOnlyRuns, prependText, removeRest, replaceText, testTscCompileLike, TestTscEdit, TscCompileSystem, verifyTsc, verifyTscCompileLike, verifyTscWithEdits, VerifyTscWithEditsInput } from "../tsc/helpers";
|
||||
|
||||
describe("unittests:: tsbuild:: outFile::", () => {
|
||||
let outFileFs: vfs.FileSystem;
|
||||
let outFileWithBuildFs: vfs.FileSystem;
|
||||
before(() => {
|
||||
outFileFs = ts.loadProjectFromDisk("tests/projects/outfile-concat");
|
||||
outFileFs = loadProjectFromDisk("tests/projects/outfile-concat");
|
||||
});
|
||||
after(() => {
|
||||
outFileFs = undefined!;
|
||||
@@ -32,17 +33,17 @@ describe("unittests:: tsbuild:: outFile::", () => {
|
||||
baselineOnly,
|
||||
additionalCommandLineArgs,
|
||||
}: VerifyOutFileScenarioInput) {
|
||||
const edits: ts.TestTscEdit[] = [];
|
||||
const edits: TestTscEdit[] = [];
|
||||
if (!ignoreDtsChanged) {
|
||||
edits.push({
|
||||
subScenario: "incremental-declaration-changes",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/first/first_PART1.ts", "Hello", "Hola"),
|
||||
modifyFs: fs => replaceText(fs, "/src/first/first_PART1.ts", "Hello", "Hola"),
|
||||
});
|
||||
}
|
||||
if (!ignoreDtsUnchanged) {
|
||||
edits.push({
|
||||
subScenario: "incremental-declaration-doesnt-change",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/first/first_PART1.ts", "console.log(s);"),
|
||||
modifyFs: fs => appendText(fs, "/src/first/first_PART1.ts", "console.log(s);"),
|
||||
});
|
||||
}
|
||||
if (modifyAgainFs) {
|
||||
@@ -51,7 +52,7 @@ describe("unittests:: tsbuild:: outFile::", () => {
|
||||
modifyFs: modifyAgainFs
|
||||
});
|
||||
}
|
||||
const input: ts.VerifyTscWithEditsInput = {
|
||||
const input: VerifyTscWithEditsInput = {
|
||||
subScenario,
|
||||
fs: () => outFileFs,
|
||||
scenario: "outfile-concat",
|
||||
@@ -62,8 +63,8 @@ describe("unittests:: tsbuild:: outFile::", () => {
|
||||
edits,
|
||||
};
|
||||
return edits.length ?
|
||||
ts.verifyTscWithEdits(input) :
|
||||
ts.verifyTsc(input);
|
||||
verifyTscWithEdits(input) :
|
||||
verifyTsc(input);
|
||||
}
|
||||
|
||||
// Verify initial + incremental edits
|
||||
@@ -80,7 +81,7 @@ describe("unittests:: tsbuild:: outFile::", () => {
|
||||
// Verify baseline with build info + dts unChanged
|
||||
verifyOutFileScenario({
|
||||
subScenario: "when final project is not composite but uses project references",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/third/tsconfig.json", `"composite": true,`, ""),
|
||||
modifyFs: fs => replaceText(fs, "/src/third/tsconfig.json", `"composite": true,`, ""),
|
||||
ignoreDtsChanged: true,
|
||||
baselineOnly: true
|
||||
});
|
||||
@@ -88,7 +89,7 @@ describe("unittests:: tsbuild:: outFile::", () => {
|
||||
// Verify baseline with build info
|
||||
verifyOutFileScenario({
|
||||
subScenario: "when final project is not composite but incremental",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/third/tsconfig.json", `"composite": true,`, `"incremental": true,`),
|
||||
modifyFs: fs => replaceText(fs, "/src/third/tsconfig.json", `"composite": true,`, `"incremental": true,`),
|
||||
ignoreDtsChanged: true,
|
||||
ignoreDtsUnchanged: true,
|
||||
baselineOnly: true
|
||||
@@ -97,7 +98,7 @@ describe("unittests:: tsbuild:: outFile::", () => {
|
||||
// Verify baseline with build info
|
||||
verifyOutFileScenario({
|
||||
subScenario: "when final project specifies tsBuildInfoFile",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/third/tsconfig.json", `"composite": true,`, `"composite": true,
|
||||
modifyFs: fs => replaceText(fs, "/src/third/tsconfig.json", `"composite": true,`, `"composite": true,
|
||||
"tsBuildInfoFile": "./thirdjs/output/third.tsbuildinfo",`),
|
||||
ignoreDtsChanged: true,
|
||||
ignoreDtsUnchanged: true,
|
||||
@@ -108,22 +109,22 @@ describe("unittests:: tsbuild:: outFile::", () => {
|
||||
if (outFileWithBuildFs) return outFileWithBuildFs;
|
||||
const fs = outFileFs.shadow();
|
||||
const sys = new fakes.System(fs, { executingFilePath: "/lib/tsc" });
|
||||
const host = ts.createSolutionBuilderHostForBaseline(sys as ts.TscCompileSystem);
|
||||
const host = createSolutionBuilderHostForBaseline(sys as TscCompileSystem);
|
||||
const builder = ts.createSolutionBuilder(host, ["/src/third"], { dry: false, force: false, verbose: true });
|
||||
builder.build();
|
||||
fs.makeReadonly();
|
||||
return outFileWithBuildFs = fs;
|
||||
}
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "outFile",
|
||||
subScenario: "clean projects",
|
||||
fs: getOutFileFsAfterBuild,
|
||||
commandLineArgs: ["--b", "/src/third", "--clean"],
|
||||
edits: ts.noChangeOnlyRuns
|
||||
edits: noChangeOnlyRuns
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "outFile",
|
||||
subScenario: "verify buildInfo absence results in new build",
|
||||
fs: getOutFileFsAfterBuild,
|
||||
@@ -131,50 +132,50 @@ describe("unittests:: tsbuild:: outFile::", () => {
|
||||
modifyFs: fs => fs.unlinkSync("/src/first/bin/first-output.tsbuildinfo"),
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "outFile",
|
||||
subScenario: "tsbuildinfo is not generated when incremental is set to false",
|
||||
fs: () => outFileFs,
|
||||
commandLineArgs: ["--b", "/src/third", "--verbose"],
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/third/tsconfig.json", `"composite": true,`, ""),
|
||||
modifyFs: fs => replaceText(fs, "/src/third/tsconfig.json", `"composite": true,`, ""),
|
||||
});
|
||||
|
||||
ts.verifyTscCompileLike(ts.testTscCompileLike, {
|
||||
verifyTscCompileLike(testTscCompileLike, {
|
||||
scenario: "outFile",
|
||||
subScenario: "rebuilds completely when version in tsbuildinfo doesnt match ts version",
|
||||
fs: getOutFileFsAfterBuild,
|
||||
commandLineArgs: ["--b", "/src/third", "--verbose"],
|
||||
compile: sys => {
|
||||
// Buildinfo will have version which does not match with current ts version
|
||||
const buildHost = ts.createSolutionBuilderHostForBaseline(sys, "FakeTSCurrentVersion");
|
||||
const buildHost = createSolutionBuilderHostForBaseline(sys, "FakeTSCurrentVersion");
|
||||
const builder = ts.createSolutionBuilder(buildHost, ["/src/third"], { verbose: true });
|
||||
sys.exit(builder.build());
|
||||
}
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "outFile",
|
||||
subScenario: "rebuilds completely when command line incremental flag changes between non dts changes",
|
||||
fs: () => outFileFs,
|
||||
// Make non composite third project
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/third/tsconfig.json", `"composite": true,`, ""),
|
||||
modifyFs: fs => replaceText(fs, "/src/third/tsconfig.json", `"composite": true,`, ""),
|
||||
// Build with command line incremental
|
||||
commandLineArgs: ["--b", "/src/third", "--i", "--verbose"],
|
||||
edits: [
|
||||
{
|
||||
subScenario: "Make non incremental build with change in file that doesnt affect dts",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/first/first_PART1.ts", "console.log(s);"),
|
||||
modifyFs: fs => appendText(fs, "/src/first/first_PART1.ts", "console.log(s);"),
|
||||
commandLineArgs: ["--b", "/src/third", "--verbose"],
|
||||
},
|
||||
{
|
||||
subScenario: "Make incremental build with change in file that doesnt affect dts",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/first/first_PART1.ts", "console.log(s);"),
|
||||
modifyFs: fs => appendText(fs, "/src/first/first_PART1.ts", "console.log(s);"),
|
||||
commandLineArgs: ["--b", "/src/third", "--verbose", "--incremental"],
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "outFile",
|
||||
subScenario: "when input file text does not change but its modified time changes",
|
||||
fs: () => outFileFs,
|
||||
@@ -190,25 +191,25 @@ describe("unittests:: tsbuild:: outFile::", () => {
|
||||
]
|
||||
});
|
||||
|
||||
ts.verifyTscCompileLike(ts.testTscCompileLike, {
|
||||
verifyTscCompileLike(testTscCompileLike, {
|
||||
scenario: "outFile",
|
||||
subScenario: "builds till project specified",
|
||||
fs: () => outFileFs,
|
||||
commandLineArgs: ["--build", "/src/second/tsconfig.json"],
|
||||
compile: sys => {
|
||||
const buildHost = ts.createSolutionBuilderHostForBaseline(sys);
|
||||
const buildHost = createSolutionBuilderHostForBaseline(sys);
|
||||
const builder = ts.createSolutionBuilder(buildHost, ["/src/third/tsconfig.json"], {});
|
||||
sys.exit(builder.build("/src/second/tsconfig.json"));
|
||||
}
|
||||
});
|
||||
|
||||
ts.verifyTscCompileLike(ts.testTscCompileLike, {
|
||||
verifyTscCompileLike(testTscCompileLike, {
|
||||
scenario: "outFile",
|
||||
subScenario: "cleans till project specified",
|
||||
fs: getOutFileFsAfterBuild,
|
||||
commandLineArgs: ["--build", "--clean", "/src/second/tsconfig.json"],
|
||||
compile: sys => {
|
||||
const buildHost = ts.createSolutionBuilderHostForBaseline(sys);
|
||||
const buildHost = createSolutionBuilderHostForBaseline(sys);
|
||||
const builder = ts.createSolutionBuilder(buildHost, ["/src/third/tsconfig.json"], { verbose: true });
|
||||
sys.exit(builder.clean("/src/second/tsconfig.json"));
|
||||
}
|
||||
@@ -221,18 +222,18 @@ describe("unittests:: tsbuild:: outFile::", () => {
|
||||
verifyOutFileScenario({
|
||||
subScenario: "strict in all projects",
|
||||
modifyFs: fs => {
|
||||
ts.enableStrict(fs, "/src/first/tsconfig.json");
|
||||
ts.enableStrict(fs, "/src/second/tsconfig.json");
|
||||
ts.enableStrict(fs, "/src/third/tsconfig.json");
|
||||
enableStrict(fs, "/src/first/tsconfig.json");
|
||||
enableStrict(fs, "/src/second/tsconfig.json");
|
||||
enableStrict(fs, "/src/third/tsconfig.json");
|
||||
},
|
||||
modifyAgainFs: fs => ts.addTestPrologue(fs, "/src/first/first_PART1.ts", `"myPrologue"`)
|
||||
modifyAgainFs: fs => addTestPrologue(fs, "/src/first/first_PART1.ts", `"myPrologue"`)
|
||||
});
|
||||
|
||||
// Verify ignore dtsChanged
|
||||
verifyOutFileScenario({
|
||||
subScenario: "strict in one dependency",
|
||||
modifyFs: fs => ts.enableStrict(fs, "/src/second/tsconfig.json"),
|
||||
modifyAgainFs: fs => ts.addTestPrologue(fs, "src/first/first_PART1.ts", `"myPrologue"`),
|
||||
modifyFs: fs => enableStrict(fs, "/src/second/tsconfig.json"),
|
||||
modifyAgainFs: fs => addTestPrologue(fs, "src/first/first_PART1.ts", `"myPrologue"`),
|
||||
ignoreDtsChanged: true,
|
||||
baselineOnly: true
|
||||
});
|
||||
@@ -241,28 +242,28 @@ describe("unittests:: tsbuild:: outFile::", () => {
|
||||
verifyOutFileScenario({
|
||||
subScenario: "multiple prologues in all projects",
|
||||
modifyFs: fs => {
|
||||
ts.enableStrict(fs, "/src/first/tsconfig.json");
|
||||
ts.addTestPrologue(fs, "/src/first/first_PART1.ts", `"myPrologue"`);
|
||||
ts.enableStrict(fs, "/src/second/tsconfig.json");
|
||||
ts.addTestPrologue(fs, "/src/second/second_part1.ts", `"myPrologue"`);
|
||||
ts.addTestPrologue(fs, "/src/second/second_part2.ts", `"myPrologue2";`);
|
||||
ts.enableStrict(fs, "/src/third/tsconfig.json");
|
||||
ts.addTestPrologue(fs, "/src/third/third_part1.ts", `"myPrologue";`);
|
||||
ts.addTestPrologue(fs, "/src/third/third_part1.ts", `"myPrologue3";`);
|
||||
enableStrict(fs, "/src/first/tsconfig.json");
|
||||
addTestPrologue(fs, "/src/first/first_PART1.ts", `"myPrologue"`);
|
||||
enableStrict(fs, "/src/second/tsconfig.json");
|
||||
addTestPrologue(fs, "/src/second/second_part1.ts", `"myPrologue"`);
|
||||
addTestPrologue(fs, "/src/second/second_part2.ts", `"myPrologue2";`);
|
||||
enableStrict(fs, "/src/third/tsconfig.json");
|
||||
addTestPrologue(fs, "/src/third/third_part1.ts", `"myPrologue";`);
|
||||
addTestPrologue(fs, "/src/third/third_part1.ts", `"myPrologue3";`);
|
||||
},
|
||||
modifyAgainFs: fs => ts.addTestPrologue(fs, "/src/first/first_PART1.ts", `"myPrologue5"`)
|
||||
modifyAgainFs: fs => addTestPrologue(fs, "/src/first/first_PART1.ts", `"myPrologue5"`)
|
||||
});
|
||||
|
||||
// Verify ignore dtsChanged
|
||||
verifyOutFileScenario({
|
||||
subScenario: "multiple prologues in different projects",
|
||||
modifyFs: fs => {
|
||||
ts.enableStrict(fs, "/src/first/tsconfig.json");
|
||||
ts.addTestPrologue(fs, "/src/second/second_part1.ts", `"myPrologue"`);
|
||||
ts.addTestPrologue(fs, "/src/second/second_part2.ts", `"myPrologue2";`);
|
||||
ts.enableStrict(fs, "/src/third/tsconfig.json");
|
||||
enableStrict(fs, "/src/first/tsconfig.json");
|
||||
addTestPrologue(fs, "/src/second/second_part1.ts", `"myPrologue"`);
|
||||
addTestPrologue(fs, "/src/second/second_part2.ts", `"myPrologue2";`);
|
||||
enableStrict(fs, "/src/third/tsconfig.json");
|
||||
},
|
||||
modifyAgainFs: fs => ts.addTestPrologue(fs, "/src/first/first_PART1.ts", `"myPrologue5"`),
|
||||
modifyAgainFs: fs => addTestPrologue(fs, "/src/first/first_PART1.ts", `"myPrologue5"`),
|
||||
ignoreDtsChanged: true,
|
||||
baselineOnly: true
|
||||
});
|
||||
@@ -275,17 +276,17 @@ describe("unittests:: tsbuild:: outFile::", () => {
|
||||
verifyOutFileScenario({
|
||||
subScenario: "shebang in all projects",
|
||||
modifyFs: fs => {
|
||||
ts.addShebang(fs, "first", "first_PART1");
|
||||
ts.addShebang(fs, "first", "first_part2");
|
||||
ts.addShebang(fs, "second", "second_part1");
|
||||
ts.addShebang(fs, "third", "third_part1");
|
||||
addShebang(fs, "first", "first_PART1");
|
||||
addShebang(fs, "first", "first_part2");
|
||||
addShebang(fs, "second", "second_part1");
|
||||
addShebang(fs, "third", "third_part1");
|
||||
},
|
||||
});
|
||||
|
||||
// Verify ignore dtsChanged
|
||||
verifyOutFileScenario({
|
||||
subScenario: "shebang in only one dependency project",
|
||||
modifyFs: fs => ts.addShebang(fs, "second", "second_part1"),
|
||||
modifyFs: fs => addShebang(fs, "second", "second_part1"),
|
||||
ignoreDtsChanged: true,
|
||||
baselineOnly: true
|
||||
});
|
||||
@@ -297,21 +298,21 @@ describe("unittests:: tsbuild:: outFile::", () => {
|
||||
verifyOutFileScenario({
|
||||
subScenario: "emitHelpers in all projects",
|
||||
modifyFs: fs => {
|
||||
ts.addRest(fs, "first", "first_PART1");
|
||||
ts.addRest(fs, "second", "second_part1");
|
||||
ts.addRest(fs, "third", "third_part1");
|
||||
addRest(fs, "first", "first_PART1");
|
||||
addRest(fs, "second", "second_part1");
|
||||
addRest(fs, "third", "third_part1");
|
||||
},
|
||||
modifyAgainFs: fs => ts.removeRest(fs, "first", "first_PART1")
|
||||
modifyAgainFs: fs => removeRest(fs, "first", "first_PART1")
|
||||
});
|
||||
|
||||
// Verify ignore dtsChanged
|
||||
verifyOutFileScenario({
|
||||
subScenario: "emitHelpers in only one dependency project",
|
||||
modifyFs: fs => {
|
||||
ts.addStubFoo(fs, "first", "first_PART1");
|
||||
ts.addRest(fs, "second", "second_part1");
|
||||
addStubFoo(fs, "first", "first_PART1");
|
||||
addRest(fs, "second", "second_part1");
|
||||
},
|
||||
modifyAgainFs: fs => ts.changeStubToRest(fs, "first", "first_PART1"),
|
||||
modifyAgainFs: fs => changeStubToRest(fs, "first", "first_PART1"),
|
||||
ignoreDtsChanged: true,
|
||||
baselineOnly: true
|
||||
});
|
||||
@@ -320,14 +321,14 @@ describe("unittests:: tsbuild:: outFile::", () => {
|
||||
verifyOutFileScenario({
|
||||
subScenario: "multiple emitHelpers in all projects",
|
||||
modifyFs: fs => {
|
||||
ts.addRest(fs, "first", "first_PART1");
|
||||
ts.addSpread(fs, "first", "first_part3");
|
||||
ts.addRest(fs, "second", "second_part1");
|
||||
ts.addSpread(fs, "second", "second_part2");
|
||||
ts.addRest(fs, "third", "third_part1");
|
||||
ts.addSpread(fs, "third", "third_part1");
|
||||
addRest(fs, "first", "first_PART1");
|
||||
addSpread(fs, "first", "first_part3");
|
||||
addRest(fs, "second", "second_part1");
|
||||
addSpread(fs, "second", "second_part2");
|
||||
addRest(fs, "third", "third_part1");
|
||||
addSpread(fs, "third", "third_part1");
|
||||
},
|
||||
modifyAgainFs: fs => ts.removeRest(fs, "first", "first_PART1"),
|
||||
modifyAgainFs: fs => removeRest(fs, "first", "first_PART1"),
|
||||
ignoreDtsChanged: true,
|
||||
baselineOnly: true
|
||||
});
|
||||
@@ -336,11 +337,11 @@ describe("unittests:: tsbuild:: outFile::", () => {
|
||||
verifyOutFileScenario({
|
||||
subScenario: "multiple emitHelpers in different projects",
|
||||
modifyFs: fs => {
|
||||
ts.addRest(fs, "first", "first_PART1");
|
||||
ts.addSpread(fs, "second", "second_part1");
|
||||
ts.addRest(fs, "third", "third_part1");
|
||||
addRest(fs, "first", "first_PART1");
|
||||
addSpread(fs, "second", "second_part1");
|
||||
addRest(fs, "third", "third_part1");
|
||||
},
|
||||
modifyAgainFs: fs => ts.removeRest(fs, "first", "first_PART1"),
|
||||
modifyAgainFs: fs => removeRest(fs, "first", "first_PART1"),
|
||||
ignoreDtsChanged: true,
|
||||
baselineOnly: true
|
||||
});
|
||||
@@ -353,16 +354,16 @@ describe("unittests:: tsbuild:: outFile::", () => {
|
||||
verifyOutFileScenario({
|
||||
subScenario: "triple slash refs in all projects",
|
||||
modifyFs: fs => {
|
||||
ts.addTripleSlashRef(fs, "first", "first_part2");
|
||||
ts.addTripleSlashRef(fs, "second", "second_part1");
|
||||
ts.addTripleSlashRef(fs, "third", "third_part1");
|
||||
addTripleSlashRef(fs, "first", "first_part2");
|
||||
addTripleSlashRef(fs, "second", "second_part1");
|
||||
addTripleSlashRef(fs, "third", "third_part1");
|
||||
}
|
||||
});
|
||||
|
||||
// Verify ignore dtsChanged
|
||||
verifyOutFileScenario({
|
||||
subScenario: "triple slash refs in one project",
|
||||
modifyFs: fs => ts.addTripleSlashRef(fs, "second", "second_part1"),
|
||||
modifyFs: fs => addTripleSlashRef(fs, "second", "second_part1"),
|
||||
ignoreDtsChanged: true,
|
||||
baselineOnly: true
|
||||
});
|
||||
@@ -370,7 +371,7 @@ describe("unittests:: tsbuild:: outFile::", () => {
|
||||
|
||||
describe("stripInternal", () => {
|
||||
function disableRemoveComments(fs: vfs.FileSystem, file: string) {
|
||||
ts.replaceText(fs, file, `"removeComments": true`, `"removeComments": false`);
|
||||
replaceText(fs, file, `"removeComments": true`, `"removeComments": false`);
|
||||
}
|
||||
|
||||
function diableRemoveCommentsInAll(fs: vfs.FileSystem) {
|
||||
@@ -380,7 +381,7 @@ describe("unittests:: tsbuild:: outFile::", () => {
|
||||
}
|
||||
|
||||
function stripInternalOfThird(fs: vfs.FileSystem) {
|
||||
ts.replaceText(fs, "/src/third/tsconfig.json", `"declaration": true,`, `"declaration": true,
|
||||
replaceText(fs, "/src/third/tsconfig.json", `"declaration": true,`, `"declaration": true,
|
||||
"stripInternal": true,`);
|
||||
}
|
||||
|
||||
@@ -390,8 +391,8 @@ describe("unittests:: tsbuild:: outFile::", () => {
|
||||
diableRemoveCommentsInAll(fs);
|
||||
}
|
||||
stripInternalOfThird(fs);
|
||||
ts.replaceText(fs, "/src/first/first_PART1.ts", "interface", `${internal} interface`);
|
||||
ts.appendText(fs, "/src/second/second_part1.ts", `
|
||||
replaceText(fs, "/src/first/first_PART1.ts", "interface", `${internal} interface`);
|
||||
appendText(fs, "/src/second/second_part1.ts", `
|
||||
class normalC {
|
||||
${internal} constructor() { }
|
||||
${internal} prop: string;
|
||||
@@ -423,14 +424,14 @@ ${internal} enum internalEnum { a, b, c }`);
|
||||
verifyOutFileScenario({
|
||||
subScenario: "stripInternal",
|
||||
modifyFs: stripInternalScenario,
|
||||
modifyAgainFs: fs => ts.replaceText(fs, "/src/first/first_PART1.ts", `/*@internal*/ interface`, "interface"),
|
||||
modifyAgainFs: fs => replaceText(fs, "/src/first/first_PART1.ts", `/*@internal*/ interface`, "interface"),
|
||||
});
|
||||
|
||||
// Verify ignore dtsChanged
|
||||
verifyOutFileScenario({
|
||||
subScenario: "stripInternal with comments emit enabled",
|
||||
modifyFs: fs => stripInternalScenario(fs, /*removeCommentsDisabled*/ true),
|
||||
modifyAgainFs: fs => ts.replaceText(fs, "/src/first/first_PART1.ts", `/*@internal*/ interface`, "interface"),
|
||||
modifyAgainFs: fs => replaceText(fs, "/src/first/first_PART1.ts", `/*@internal*/ interface`, "interface"),
|
||||
ignoreDtsChanged: true,
|
||||
baselineOnly: true
|
||||
});
|
||||
@@ -439,7 +440,7 @@ ${internal} enum internalEnum { a, b, c }`);
|
||||
verifyOutFileScenario({
|
||||
subScenario: "stripInternal jsdoc style comment",
|
||||
modifyFs: fs => stripInternalScenario(fs, /*removeCommentsDisabled*/ false, /*jsDocStyle*/ true),
|
||||
modifyAgainFs: fs => ts.replaceText(fs, "/src/first/first_PART1.ts", `/**@internal*/ interface`, "interface"),
|
||||
modifyAgainFs: fs => replaceText(fs, "/src/first/first_PART1.ts", `/**@internal*/ interface`, "interface"),
|
||||
ignoreDtsChanged: true,
|
||||
baselineOnly: true
|
||||
});
|
||||
@@ -454,9 +455,9 @@ ${internal} enum internalEnum { a, b, c }`);
|
||||
|
||||
describe("with three levels of project dependency", () => {
|
||||
function makeOneTwoThreeDependOrder(fs: vfs.FileSystem) {
|
||||
ts.replaceText(fs, "/src/second/tsconfig.json", "[", `[
|
||||
replaceText(fs, "/src/second/tsconfig.json", "[", `[
|
||||
{ "path": "../first", "prepend": true }`);
|
||||
ts.replaceText(fs, "/src/third/tsconfig.json", `{ "path": "../first", "prepend": true },`, "");
|
||||
replaceText(fs, "/src/third/tsconfig.json", `{ "path": "../first", "prepend": true },`, "");
|
||||
}
|
||||
|
||||
function stripInternalWithDependentOrder(fs: vfs.FileSystem, removeCommentsDisabled?: boolean, jsDocStyle?: boolean) {
|
||||
@@ -468,14 +469,14 @@ ${internal} enum internalEnum { a, b, c }`);
|
||||
verifyOutFileScenario({
|
||||
subScenario: "stripInternal when one-two-three are prepended in order",
|
||||
modifyFs: stripInternalWithDependentOrder,
|
||||
modifyAgainFs: fs => ts.replaceText(fs, "/src/first/first_PART1.ts", `/*@internal*/ interface`, "interface"),
|
||||
modifyAgainFs: fs => replaceText(fs, "/src/first/first_PART1.ts", `/*@internal*/ interface`, "interface"),
|
||||
});
|
||||
|
||||
// Verify ignore dtsChanged
|
||||
verifyOutFileScenario({
|
||||
subScenario: "stripInternal with comments emit enabled when one-two-three are prepended in order",
|
||||
modifyFs: fs => stripInternalWithDependentOrder(fs, /*removeCommentsDisabled*/ true),
|
||||
modifyAgainFs: fs => ts.replaceText(fs, "/src/first/first_PART1.ts", `/*@internal*/ interface`, "interface"),
|
||||
modifyAgainFs: fs => replaceText(fs, "/src/first/first_PART1.ts", `/*@internal*/ interface`, "interface"),
|
||||
ignoreDtsChanged: true,
|
||||
baselineOnly: true
|
||||
});
|
||||
@@ -484,7 +485,7 @@ ${internal} enum internalEnum { a, b, c }`);
|
||||
verifyOutFileScenario({
|
||||
subScenario: "stripInternal jsdoc style comment when one-two-three are prepended in order",
|
||||
modifyFs: fs => stripInternalWithDependentOrder(fs, /*removeCommentsDisabled*/ false, /*jsDocStyle*/ true),
|
||||
modifyAgainFs: fs => ts.replaceText(fs, "/src/first/first_PART1.ts", `/**@internal*/ interface`, "interface"),
|
||||
modifyAgainFs: fs => replaceText(fs, "/src/first/first_PART1.ts", `/**@internal*/ interface`, "interface"),
|
||||
ignoreDtsChanged: true,
|
||||
baselineOnly: true
|
||||
});
|
||||
@@ -503,7 +504,7 @@ ${internal} enum internalEnum { a, b, c }`);
|
||||
subScenario: "stripInternal baseline when internal is inside another internal",
|
||||
modifyFs: fs => {
|
||||
stripInternalOfThird(fs);
|
||||
ts.prependText(fs, "/src/first/first_PART1.ts", `namespace ts {
|
||||
prependText(fs, "/src/first/first_PART1.ts", `namespace ts {
|
||||
/* @internal */
|
||||
/**
|
||||
* Subset of properties from SourceFile that are used in multiple utility functions
|
||||
@@ -542,7 +543,7 @@ ${internal} enum internalEnum { a, b, c }`);
|
||||
subScenario: "stripInternal when few members of enum are internal",
|
||||
modifyFs: fs => {
|
||||
stripInternalOfThird(fs);
|
||||
ts.prependText(fs, "/src/first/first_PART1.ts", `enum TokenFlags {
|
||||
prependText(fs, "/src/first/first_PART1.ts", `enum TokenFlags {
|
||||
None = 0,
|
||||
/* @internal */
|
||||
PrecedingLineBreak = 1 << 0,
|
||||
@@ -624,9 +625,9 @@ ${internal} enum internalEnum { a, b, c }`);
|
||||
subScenario: "declarationMap and sourceMap disabled",
|
||||
modifyFs: fs => {
|
||||
makeThirdEmptySourceFile(fs);
|
||||
ts.replaceText(fs, "/src/third/tsconfig.json", `"composite": true,`, "");
|
||||
ts.replaceText(fs, "/src/third/tsconfig.json", `"sourceMap": true,`, "");
|
||||
ts.replaceText(fs, "/src/third/tsconfig.json", `"declarationMap": true,`, "");
|
||||
replaceText(fs, "/src/third/tsconfig.json", `"composite": true,`, "");
|
||||
replaceText(fs, "/src/third/tsconfig.json", `"sourceMap": true,`, "");
|
||||
replaceText(fs, "/src/third/tsconfig.json", `"declarationMap": true,`, "");
|
||||
},
|
||||
ignoreDtsChanged: true,
|
||||
ignoreDtsUnchanged: true,
|
||||
@@ -635,25 +636,25 @@ ${internal} enum internalEnum { a, b, c }`);
|
||||
});
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "outFile",
|
||||
subScenario: "non module projects without prepend",
|
||||
fs: () => outFileFs,
|
||||
commandLineArgs: ["--b", "/src/third", "--verbose"],
|
||||
modifyFs: fs => {
|
||||
// No prepend
|
||||
ts.replaceText(fs, "/src/third/tsconfig.json", `{ "path": "../first", "prepend": true }`, `{ "path": "../first" }`);
|
||||
ts.replaceText(fs, "/src/third/tsconfig.json", `{ "path": "../second", "prepend": true }`, `{ "path": "../second" }`);
|
||||
replaceText(fs, "/src/third/tsconfig.json", `{ "path": "../first", "prepend": true }`, `{ "path": "../first" }`);
|
||||
replaceText(fs, "/src/third/tsconfig.json", `{ "path": "../second", "prepend": true }`, `{ "path": "../second" }`);
|
||||
|
||||
// Non Modules
|
||||
ts.replaceText(fs, "/src/first/tsconfig.json", `"composite": true,`, `"composite": true, "module": "none",`);
|
||||
ts.replaceText(fs, "/src/second/tsconfig.json", `"composite": true,`, `"composite": true, "module": "none",`);
|
||||
ts.replaceText(fs, "/src/third/tsconfig.json", `"composite": true,`, `"composite": true, "module": "none",`);
|
||||
replaceText(fs, "/src/first/tsconfig.json", `"composite": true,`, `"composite": true, "module": "none",`);
|
||||
replaceText(fs, "/src/second/tsconfig.json", `"composite": true,`, `"composite": true, "module": "none",`);
|
||||
replaceText(fs, "/src/third/tsconfig.json", `"composite": true,`, `"composite": true, "module": "none",`);
|
||||
|
||||
// Own file emit
|
||||
ts.replaceText(fs, "/src/first/tsconfig.json", `"outFile": "./bin/first-output.js",`, "");
|
||||
ts.replaceText(fs, "/src/second/tsconfig.json", `"outFile": "../2/second-output.js",`, "");
|
||||
ts.replaceText(fs, "/src/third/tsconfig.json", `"outFile": "./thirdjs/output/third-output.js",`, "");
|
||||
replaceText(fs, "/src/first/tsconfig.json", `"outFile": "./bin/first-output.js",`, "");
|
||||
replaceText(fs, "/src/second/tsconfig.json", `"outFile": "../2/second-output.js",`, "");
|
||||
replaceText(fs, "/src/third/tsconfig.json", `"outFile": "./thirdjs/output/third-output.js",`, "");
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,26 +1,27 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as fakes from "../../_namespaces/fakes";
|
||||
import { loadProjectFromFiles, noChangeRun, TestTscEdit, TscCompileSystem, verifyTscWithEdits, VerifyTscWithEditsInput } from "../tsc/helpers";
|
||||
|
||||
describe("unittests:: tsbuild - output file paths", () => {
|
||||
const noChangeProject: ts.TestTscEdit = {
|
||||
const noChangeProject: TestTscEdit = {
|
||||
modifyFs: ts.noop,
|
||||
subScenario: "Normal build without change, that does not block emit on error to show files that get emitted",
|
||||
commandLineArgs: ["-p", "/src/tsconfig.json"],
|
||||
};
|
||||
const edits: ts.TestTscEdit[] = [
|
||||
ts.noChangeRun,
|
||||
const edits: TestTscEdit[] = [
|
||||
noChangeRun,
|
||||
noChangeProject,
|
||||
];
|
||||
|
||||
function verify(input: Pick<ts.VerifyTscWithEditsInput, "subScenario" | "fs" | "edits">, expectedOuptutNames: readonly string[]) {
|
||||
ts.verifyTscWithEdits({
|
||||
function verify(input: Pick<VerifyTscWithEditsInput, "subScenario" | "fs" | "edits">, expectedOuptutNames: readonly string[]) {
|
||||
verifyTscWithEdits({
|
||||
scenario: "outputPaths",
|
||||
commandLineArgs: ["--b", "/src/tsconfig.json", "-v"],
|
||||
...input
|
||||
});
|
||||
|
||||
it("verify getOutputFileNames", () => {
|
||||
const sys = new fakes.System(input.fs().makeReadonly(), { executingFilePath: "/lib/tsc" }) as ts.TscCompileSystem;
|
||||
const sys = new fakes.System(input.fs().makeReadonly(), { executingFilePath: "/lib/tsc" }) as TscCompileSystem;
|
||||
|
||||
assert.deepEqual(
|
||||
ts.getOutputFileNames(
|
||||
@@ -35,7 +36,7 @@ describe("unittests:: tsbuild - output file paths", () => {
|
||||
|
||||
verify({
|
||||
subScenario: "when rootDir is not specified",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/src/index.ts": "export const x = 10;",
|
||||
"/src/tsconfig.json": JSON.stringify({
|
||||
compilerOptions: {
|
||||
@@ -48,7 +49,7 @@ describe("unittests:: tsbuild - output file paths", () => {
|
||||
|
||||
verify({
|
||||
subScenario: "when rootDir is not specified and is composite",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/src/index.ts": "export const x = 10;",
|
||||
"/src/tsconfig.json": JSON.stringify({
|
||||
compilerOptions: {
|
||||
@@ -62,7 +63,7 @@ describe("unittests:: tsbuild - output file paths", () => {
|
||||
|
||||
verify({
|
||||
subScenario: "when rootDir is specified",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/src/index.ts": "export const x = 10;",
|
||||
"/src/tsconfig.json": JSON.stringify({
|
||||
compilerOptions: {
|
||||
@@ -76,7 +77,7 @@ describe("unittests:: tsbuild - output file paths", () => {
|
||||
|
||||
verify({
|
||||
subScenario: "when rootDir is specified but not all files belong to rootDir",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/src/index.ts": "export const x = 10;",
|
||||
"/src/types/type.ts": "export type t = string;",
|
||||
"/src/tsconfig.json": JSON.stringify({
|
||||
@@ -91,7 +92,7 @@ describe("unittests:: tsbuild - output file paths", () => {
|
||||
|
||||
verify({
|
||||
subScenario: "when rootDir is specified but not all files belong to rootDir and is composite",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/src/index.ts": "export const x = 10;",
|
||||
"/src/types/type.ts": "export type t = string;",
|
||||
"/src/tsconfig.json": JSON.stringify({
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as fakes from "../../_namespaces/fakes";
|
||||
import * as vfs from "../../_namespaces/vfs";
|
||||
import { baselinePrograms, commandLineCallbacks, loadProjectFromFiles, toPathWithSystem, TscCompileSystem, verifyTscBaseline } from "../tsc/helpers";
|
||||
|
||||
describe("unittests:: tsbuild:: Public API with custom transformers when passed to build", () => {
|
||||
let sys: ts.TscCompileSystem;
|
||||
let sys: TscCompileSystem;
|
||||
before(() => {
|
||||
const inputFs = ts.loadProjectFromFiles({
|
||||
const inputFs = loadProjectFromFiles({
|
||||
"/src/tsconfig.json": JSON.stringify({
|
||||
references: [
|
||||
{ path: "./shared/tsconfig.json" },
|
||||
@@ -36,7 +37,7 @@ export function f22() { } // trailing`,
|
||||
const fs = inputFs.shadow();
|
||||
|
||||
// Create system
|
||||
sys = new fakes.System(fs, { executingFilePath: "/lib/tsc" }) as ts.TscCompileSystem;
|
||||
sys = new fakes.System(fs, { executingFilePath: "/lib/tsc" }) as TscCompileSystem;
|
||||
fakes.patchHostForBuildInfoReadWrite(sys);
|
||||
const commandLineArgs = ["--b", "/src/tsconfig.json"];
|
||||
sys.write(`${sys.getExecutingFilePath()} ${commandLineArgs.join(" ")}\n`);
|
||||
@@ -44,12 +45,12 @@ export function f22() { } // trailing`,
|
||||
const writtenFiles = sys.writtenFiles = new ts.Set();
|
||||
const originalWriteFile = sys.writeFile;
|
||||
sys.writeFile = (fileName, content, writeByteOrderMark) => {
|
||||
const path = ts.toPathWithSystem(sys, fileName);
|
||||
const path = toPathWithSystem(sys, fileName);
|
||||
assert.isFalse(writtenFiles.has(path));
|
||||
writtenFiles.add(path);
|
||||
return originalWriteFile.call(sys, fileName, content, writeByteOrderMark);
|
||||
};
|
||||
const { cb, getPrograms } = ts.commandLineCallbacks(sys, /*originalReadCall*/ undefined);
|
||||
const { cb, getPrograms } = commandLineCallbacks(sys, /*originalReadCall*/ undefined);
|
||||
const buildHost = ts.createSolutionBuilderHost(
|
||||
sys,
|
||||
/*createProgram*/ undefined,
|
||||
@@ -64,7 +65,7 @@ export function f22() { } // trailing`,
|
||||
sys.exit(exitStatus);
|
||||
sys.write(`exitCode:: ExitStatus.${ts.ExitStatus[sys.exitCode as ts.ExitStatus]}\n`);
|
||||
const baseline: string[] = [];
|
||||
ts.tscWatch.baselinePrograms(baseline, getPrograms, ts.emptyArray, /*baselineDependencies*/ false);
|
||||
baselinePrograms(baseline, getPrograms, ts.emptyArray, /*baselineDependencies*/ false);
|
||||
sys.write(baseline.join("\n"));
|
||||
fs.makeReadonly();
|
||||
sys.baseLine = () => {
|
||||
@@ -120,5 +121,5 @@ ${patch ? vfs.formatPatch(patch) : ""}`
|
||||
after(() => {
|
||||
sys = undefined!;
|
||||
});
|
||||
ts.verifyTscBaseline(() => sys);
|
||||
verifyTscBaseline(() => sys);
|
||||
});
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as vfs from "../../_namespaces/vfs";
|
||||
import { loadProjectFromDisk, replaceText, verifyTsc } from "../tsc/helpers";
|
||||
|
||||
describe("unittests:: tsbuild:: with rootDir of project reference in parentDirectory", () => {
|
||||
let projFs: vfs.FileSystem;
|
||||
before(() => {
|
||||
projFs = ts.loadProjectFromDisk("tests/projects/projectReferenceWithRootDirInParent");
|
||||
projFs = loadProjectFromDisk("tests/projects/projectReferenceWithRootDirInParent");
|
||||
});
|
||||
|
||||
after(() => {
|
||||
projFs = undefined!; // Release the contents
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "projectReferenceWithRootDirInParent",
|
||||
subScenario: "builds correctly",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "/src/src/main", "/src/src/other"],
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "projectReferenceWithRootDirInParent",
|
||||
subScenario: "reports error for same tsbuildinfo file because no rootDir in the base",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "/src/src/main", "--verbose"],
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/tsconfig.base.json", `"rootDir": "./src/",`, ""),
|
||||
modifyFs: fs => replaceText(fs, "/src/tsconfig.base.json", `"rootDir": "./src/",`, ""),
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "projectReferenceWithRootDirInParent",
|
||||
subScenario: "reports error for same tsbuildinfo file",
|
||||
fs: () => projFs,
|
||||
@@ -42,7 +42,7 @@ describe("unittests:: tsbuild:: with rootDir of project reference in parentDirec
|
||||
},
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "projectReferenceWithRootDirInParent",
|
||||
subScenario: "reports no error when tsbuildinfo differ",
|
||||
fs: () => projFs,
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as vfs from "../../_namespaces/vfs";
|
||||
import { loadProjectFromDisk, noChangeOnlyRuns, replaceText, verifyTsc, verifyTscWithEdits } from "../tsc/helpers";
|
||||
|
||||
describe("unittests:: tsbuild:: with resolveJsonModule option on project resolveJsonModuleAndComposite", () => {
|
||||
let projFs: vfs.FileSystem;
|
||||
before(() => {
|
||||
projFs = ts.loadProjectFromDisk("tests/projects/resolveJsonModuleAndComposite");
|
||||
projFs = loadProjectFromDisk("tests/projects/resolveJsonModuleAndComposite");
|
||||
});
|
||||
|
||||
after(() => {
|
||||
projFs = undefined!; // Release the contents
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "resolveJsonModule",
|
||||
subScenario: "include only",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "/src/tsconfig_withInclude.json", "--v", "--explainFiles"],
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "resolveJsonModule",
|
||||
subScenario: "include of json along with other include",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "/src/tsconfig_withIncludeOfJson.json", "--v", "--explainFiles"],
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "resolveJsonModule",
|
||||
subScenario: "include of json along with other include and file name matches ts file",
|
||||
fs: () => projFs,
|
||||
@@ -39,45 +39,45 @@ export default hello.hello`);
|
||||
},
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "resolveJsonModule",
|
||||
subScenario: "files containing json file",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "/src/tsconfig_withFiles.json", "--v", "--explainFiles"],
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "resolveJsonModule",
|
||||
subScenario: "include and files",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "/src/tsconfig_withIncludeAndFiles.json", "--v", "--explainFiles"],
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "resolveJsonModule",
|
||||
subScenario: "sourcemap",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "src/tsconfig_withFiles.json", "--verbose", "--explainFiles"],
|
||||
modifyFs: fs => ts.replaceText(fs, "src/tsconfig_withFiles.json", `"composite": true,`, `"composite": true, "sourceMap": true,`),
|
||||
edits: ts.noChangeOnlyRuns
|
||||
modifyFs: fs => replaceText(fs, "src/tsconfig_withFiles.json", `"composite": true,`, `"composite": true, "sourceMap": true,`),
|
||||
edits: noChangeOnlyRuns
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "resolveJsonModule",
|
||||
subScenario: "without outDir",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "src/tsconfig_withFiles.json", "--verbose"],
|
||||
modifyFs: fs => ts.replaceText(fs, "src/tsconfig_withFiles.json", `"outDir": "dist",`, ""),
|
||||
edits: ts.noChangeOnlyRuns
|
||||
modifyFs: fs => replaceText(fs, "src/tsconfig_withFiles.json", `"outDir": "dist",`, ""),
|
||||
edits: noChangeOnlyRuns
|
||||
});
|
||||
});
|
||||
|
||||
describe("unittests:: tsbuild:: with resolveJsonModule option on project importJsonFromProjectReference", () => {
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "resolveJsonModule",
|
||||
subScenario: "importing json module from project reference",
|
||||
fs: () => ts.loadProjectFromDisk("tests/projects/importJsonFromProjectReference"),
|
||||
fs: () => loadProjectFromDisk("tests/projects/importJsonFromProjectReference"),
|
||||
commandLineArgs: ["--b", "src/tsconfig.json", "--verbose", "--explainFiles"],
|
||||
edits: ts.noChangeOnlyRuns
|
||||
edits: noChangeOnlyRuns
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,12 +2,14 @@ import * as ts from "../../_namespaces/ts";
|
||||
import * as vfs from "../../_namespaces/vfs";
|
||||
import * as fakes from "../../_namespaces/fakes";
|
||||
import * as Harness from "../../_namespaces/Harness";
|
||||
import { changeToHostTrackingWrittenFiles, createWatchedSystem, File, getTsBuildProjectFilePath, libFile, TestServerHost } from "../virtualFileSystemWithWatch";
|
||||
import { appendText, createSolutionBuilderHostForBaseline, libContent, loadProjectFromDisk, loadProjectFromFiles, noChangeOnlyRuns, noChangeRun, prependText, replaceText, testTscCompileLike, TestTscEdit, TscCompileSystem, verifyTsc, verifyTscCompileLike, verifyTscWithEdits } from "../tsc/helpers";
|
||||
|
||||
describe("unittests:: tsbuild:: on 'sample1' project", () => {
|
||||
let projFs: vfs.FileSystem;
|
||||
let projFsWithBuild: vfs.FileSystem;
|
||||
before(() => {
|
||||
projFs = ts.loadProjectFromDisk("tests/projects/sample1");
|
||||
projFs = loadProjectFromDisk("tests/projects/sample1");
|
||||
});
|
||||
|
||||
after(() => {
|
||||
@@ -15,9 +17,9 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => {
|
||||
projFsWithBuild = undefined!;
|
||||
});
|
||||
|
||||
function getTsBuildProjectFile(project: string, file: string): ts.tscWatch.File {
|
||||
function getTsBuildProjectFile(project: string, file: string): File {
|
||||
return {
|
||||
path: ts.TestFSWithWatch.getTsBuildProjectFilePath(project, file),
|
||||
path: getTsBuildProjectFilePath(project, file),
|
||||
content: projFs.readFileSync(`/src/${project}/${file}`, "utf8")!
|
||||
};
|
||||
}
|
||||
@@ -26,7 +28,7 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => {
|
||||
if (projFsWithBuild) return projFsWithBuild;
|
||||
const fs = projFs.shadow();
|
||||
const sys = new fakes.System(fs, { executingFilePath: "/lib/tsc" });
|
||||
const host = ts.createSolutionBuilderHostForBaseline(sys as ts.TscCompileSystem);
|
||||
const host = createSolutionBuilderHostForBaseline(sys as TscCompileSystem);
|
||||
const builder = ts.createSolutionBuilder(host, ["/src/tests"], {});
|
||||
builder.build();
|
||||
fs.makeReadonly();
|
||||
@@ -34,7 +36,7 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => {
|
||||
}
|
||||
|
||||
describe("sanity check of clean build of 'sample1' project", () => {
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "sample1",
|
||||
subScenario: "builds correctly when outDir is specified",
|
||||
fs: () => projFs,
|
||||
@@ -45,7 +47,7 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => {
|
||||
})),
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "sample1",
|
||||
subScenario: "builds correctly when declarationDir is specified",
|
||||
fs: () => projFs,
|
||||
@@ -56,17 +58,17 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => {
|
||||
})),
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "sample1",
|
||||
subScenario: "builds correctly when project is not composite or doesnt have any references",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "/src/core", "--verbose"],
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/core/tsconfig.json", `"composite": true,`, ""),
|
||||
modifyFs: fs => replaceText(fs, "/src/core/tsconfig.json", `"composite": true,`, ""),
|
||||
});
|
||||
});
|
||||
|
||||
describe("dry builds", () => {
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "sample1",
|
||||
subScenario: "does not write any files in a dry build",
|
||||
fs: () => projFs,
|
||||
@@ -75,33 +77,33 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => {
|
||||
});
|
||||
|
||||
describe("clean builds", () => {
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "sample1",
|
||||
subScenario: "removes all files it built",
|
||||
fs: getSampleFsAfterBuild,
|
||||
commandLineArgs: ["--b", "/src/tests", "--clean"],
|
||||
edits: ts.noChangeOnlyRuns
|
||||
edits: noChangeOnlyRuns
|
||||
});
|
||||
|
||||
ts.verifyTscCompileLike(ts.testTscCompileLike, {
|
||||
verifyTscCompileLike(testTscCompileLike, {
|
||||
scenario: "sample1",
|
||||
subScenario: "cleans till project specified",
|
||||
fs: getSampleFsAfterBuild,
|
||||
commandLineArgs: ["--b", "/src/logic", "--clean"],
|
||||
compile: sys => {
|
||||
const buildHost = ts.createSolutionBuilderHostForBaseline(sys);
|
||||
const buildHost = createSolutionBuilderHostForBaseline(sys);
|
||||
const builder = ts.createSolutionBuilder(buildHost, ["/src/third/tsconfig.json"], {});
|
||||
sys.exit(builder.clean("/src/logic"));
|
||||
}
|
||||
});
|
||||
|
||||
ts.verifyTscCompileLike(ts.testTscCompileLike, {
|
||||
verifyTscCompileLike(testTscCompileLike, {
|
||||
scenario: "sample1",
|
||||
subScenario: "cleaning project in not build order doesnt throw error",
|
||||
fs: getSampleFsAfterBuild,
|
||||
commandLineArgs: ["--b", "/src/logic2", "--clean"],
|
||||
compile: sys => {
|
||||
const buildHost = ts.createSolutionBuilderHostForBaseline(sys);
|
||||
const buildHost = createSolutionBuilderHostForBaseline(sys);
|
||||
const builder = ts.createSolutionBuilder(buildHost, ["/src/third/tsconfig.json"], {});
|
||||
sys.exit(builder.clean("/src/logic2"));
|
||||
}
|
||||
@@ -109,17 +111,17 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => {
|
||||
});
|
||||
|
||||
describe("force builds", () => {
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "sample1",
|
||||
subScenario: "always builds under with force option",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "/src/tests", "--force"],
|
||||
edits: ts.noChangeOnlyRuns
|
||||
edits: noChangeOnlyRuns
|
||||
});
|
||||
});
|
||||
|
||||
describe("can detect when and what to rebuild", () => {
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "sample1",
|
||||
subScenario: "can detect when and what to rebuild",
|
||||
fs: getSampleFsAfterBuild,
|
||||
@@ -133,16 +135,16 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => {
|
||||
// Update a file in the parent (without affecting types), should get fast downstream builds
|
||||
{
|
||||
subScenario: "Detects type-only changes in upstream projects",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/core/index.ts", "HELLO WORLD", "WELCOME PLANET"),
|
||||
modifyFs: fs => replaceText(fs, "/src/core/index.ts", "HELLO WORLD", "WELCOME PLANET"),
|
||||
},
|
||||
{
|
||||
subScenario: "rebuilds when tsconfig changes",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/tests/tsconfig.json", `"composite": true`, `"composite": true, "target": "es3"`),
|
||||
modifyFs: fs => replaceText(fs, "/src/tests/tsconfig.json", `"composite": true`, `"composite": true, "target": "es3"`),
|
||||
},
|
||||
]
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "sample1",
|
||||
subScenario: "when input file text does not change but its modified time changes",
|
||||
fs: () => projFs,
|
||||
@@ -158,7 +160,7 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => {
|
||||
]
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "sample1",
|
||||
subScenario: "when declarationMap changes",
|
||||
fs: () => projFs,
|
||||
@@ -166,33 +168,33 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => {
|
||||
edits: [
|
||||
{
|
||||
subScenario: "Disable declarationMap",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/core/tsconfig.json", `"declarationMap": true,`, `"declarationMap": false,`),
|
||||
modifyFs: fs => replaceText(fs, "/src/core/tsconfig.json", `"declarationMap": true,`, `"declarationMap": false,`),
|
||||
},
|
||||
{
|
||||
subScenario: "Enable declarationMap",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/core/tsconfig.json", `"declarationMap": false,`, `"declarationMap": true,`),
|
||||
modifyFs: fs => replaceText(fs, "/src/core/tsconfig.json", `"declarationMap": false,`, `"declarationMap": true,`),
|
||||
},
|
||||
]
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "sample1",
|
||||
subScenario: "indicates that it would skip builds during a dry build",
|
||||
fs: getSampleFsAfterBuild,
|
||||
commandLineArgs: ["--b", "/src/tests", "--dry"],
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "sample1",
|
||||
subScenario: "rebuilds from start if force option is set",
|
||||
fs: getSampleFsAfterBuild,
|
||||
commandLineArgs: ["--b", "/src/tests", "--verbose", "--force"],
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "sample1",
|
||||
subScenario: "tsbuildinfo has error",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/project/main.ts": "export const x = 10;",
|
||||
"/src/project/tsconfig.json": "{}",
|
||||
"/src/project/tsconfig.tsbuildinfo": "Some random string",
|
||||
@@ -200,24 +202,24 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => {
|
||||
commandLineArgs: ["--b", "src/project", "-i", "-v"],
|
||||
edits: [{
|
||||
subScenario: "tsbuildinfo written has error",
|
||||
modifyFs: fs => ts.prependText(fs, "/src/project/tsconfig.tsbuildinfo", "Some random string"),
|
||||
modifyFs: fs => prependText(fs, "/src/project/tsconfig.tsbuildinfo", "Some random string"),
|
||||
}]
|
||||
});
|
||||
|
||||
ts.verifyTscCompileLike(ts.testTscCompileLike, {
|
||||
verifyTscCompileLike(testTscCompileLike, {
|
||||
scenario: "sample1",
|
||||
subScenario: "rebuilds completely when version in tsbuildinfo doesnt match ts version",
|
||||
fs: getSampleFsAfterBuild,
|
||||
commandLineArgs: ["--b", "/src/tests", "--verbose"],
|
||||
compile: sys => {
|
||||
// Buildinfo will have version which does not match with current ts version
|
||||
const buildHost = ts.createSolutionBuilderHostForBaseline(sys, "FakeTSCurrentVersion");
|
||||
const buildHost = createSolutionBuilderHostForBaseline(sys, "FakeTSCurrentVersion");
|
||||
const builder = ts.createSolutionBuilder(buildHost, ["/src/tests"], { verbose: true });
|
||||
sys.exit(builder.build());
|
||||
}
|
||||
});
|
||||
|
||||
ts.verifyTscCompileLike(ts.testTscCompileLike, {
|
||||
verifyTscCompileLike(testTscCompileLike, {
|
||||
scenario: "sample1",
|
||||
subScenario: "does not rebuild if there is no program and bundle in the ts build info event if version doesnt match ts version",
|
||||
fs: () => {
|
||||
@@ -231,20 +233,20 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => {
|
||||
commandLineArgs: ["--b", "/src/tests", "--verbose"],
|
||||
compile: sys => {
|
||||
// Buildinfo will have version which does not match with current ts version
|
||||
const buildHost = ts.createSolutionBuilderHostForBaseline(sys, "FakeTSCurrentVersion");
|
||||
const buildHost = createSolutionBuilderHostForBaseline(sys, "FakeTSCurrentVersion");
|
||||
const builder = ts.createSolutionBuilder(buildHost, ["/src/tests"], { verbose: true });
|
||||
sys.exit(builder.build());
|
||||
},
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "sample1",
|
||||
subScenario: "rebuilds when extended config file changes",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "/src/tests", "--verbose"],
|
||||
modifyFs: fs => {
|
||||
fs.writeFileSync("/src/tests/tsconfig.base.json", JSON.stringify({ compilerOptions: { target: "es3" } }));
|
||||
ts.replaceText(fs, "/src/tests/tsconfig.json", `"references": [`, `"extends": "./tsconfig.base.json", "references": [`);
|
||||
replaceText(fs, "/src/tests/tsconfig.json", `"references": [`, `"extends": "./tsconfig.base.json", "references": [`);
|
||||
},
|
||||
edits: [{
|
||||
subScenario: "incremental-declaration-changes",
|
||||
@@ -252,25 +254,25 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => {
|
||||
}]
|
||||
});
|
||||
|
||||
ts.verifyTscCompileLike(ts.testTscCompileLike, {
|
||||
verifyTscCompileLike(testTscCompileLike, {
|
||||
scenario: "sample1",
|
||||
subScenario: "builds till project specified",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--build", "/src/logic/tsconfig.json"],
|
||||
compile: sys => {
|
||||
const buildHost = ts.createSolutionBuilderHostForBaseline(sys);
|
||||
const buildHost = createSolutionBuilderHostForBaseline(sys);
|
||||
const builder = ts.createSolutionBuilder(buildHost, ["/src/tests"], {});
|
||||
sys.exit(builder.build("/src/logic/tsconfig.json"));
|
||||
}
|
||||
});
|
||||
|
||||
ts.verifyTscCompileLike(ts.testTscCompileLike, {
|
||||
verifyTscCompileLike(testTscCompileLike, {
|
||||
scenario: "sample1",
|
||||
subScenario: "building project in not build order doesnt throw error",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--build", "/src/logic2/tsconfig.json"],
|
||||
compile: sys => {
|
||||
const buildHost = ts.createSolutionBuilderHostForBaseline(sys);
|
||||
const buildHost = createSolutionBuilderHostForBaseline(sys);
|
||||
const builder = ts.createSolutionBuilder(buildHost, ["/src/tests"], {});
|
||||
sys.exit(builder.build("/src/logic2/tsconfig.json"));
|
||||
}
|
||||
@@ -286,19 +288,19 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => {
|
||||
const testsConfig = getTsBuildProjectFile("tests", "tsconfig.json");
|
||||
const testsIndex = getTsBuildProjectFile("tests", "index.ts");
|
||||
const baseline: string[] = [];
|
||||
let oldSnap: ReturnType<ts.TestFSWithWatch.TestServerHost["snap"]> | undefined;
|
||||
const system = ts.TestFSWithWatch.changeToHostTrackingWrittenFiles(
|
||||
let oldSnap: ReturnType<TestServerHost["snap"]> | undefined;
|
||||
const system = changeToHostTrackingWrittenFiles(
|
||||
fakes.patchHostForBuildInfoReadWrite(
|
||||
ts.tscWatch.createWatchedSystem([
|
||||
createWatchedSystem([
|
||||
coreConfig, coreIndex, coreDecl, coreAnotherModule,
|
||||
logicConfig, logicIndex,
|
||||
testsConfig, testsIndex,
|
||||
ts.tscWatch.libFile
|
||||
libFile
|
||||
])
|
||||
)
|
||||
);
|
||||
|
||||
const host = ts.createSolutionBuilderHostForBaseline(system);
|
||||
const host = createSolutionBuilderHostForBaseline(system);
|
||||
const builder = ts.createSolutionBuilder(host, [testsConfig.path], {});
|
||||
baseline.push("Input::");
|
||||
baselineState();
|
||||
@@ -323,13 +325,13 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => {
|
||||
}
|
||||
});
|
||||
|
||||
ts.verifyTscCompileLike(ts.testTscCompileLike, {
|
||||
verifyTscCompileLike(testTscCompileLike, {
|
||||
scenario: "sample1",
|
||||
subScenario: "building using buildReferencedProject",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--build", "/src/logic2/tsconfig.json"],
|
||||
compile: sys => {
|
||||
const buildHost = ts.createSolutionBuilderHostForBaseline(sys);
|
||||
const buildHost = createSolutionBuilderHostForBaseline(sys);
|
||||
const builder = ts.createSolutionBuilder(buildHost, ["/src/tests"], { verbose: true });
|
||||
sys.exit(builder.buildReferences("/src/tests"));
|
||||
}
|
||||
@@ -337,13 +339,13 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => {
|
||||
});
|
||||
|
||||
describe("downstream-blocked compilations", () => {
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "sample1",
|
||||
subScenario: "does not build downstream projects if upstream projects have errors",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "/src/tests", "--verbose"],
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/logic/index.ts", "c.multiply(10, 15)", `c.muitply()`),
|
||||
edits: ts.noChangeOnlyRuns
|
||||
modifyFs: fs => replaceText(fs, "/src/logic/index.ts", "c.multiply(10, 15)", `c.muitply()`),
|
||||
edits: noChangeOnlyRuns
|
||||
});
|
||||
});
|
||||
|
||||
@@ -358,19 +360,19 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => {
|
||||
const testsConfig = getTsBuildProjectFile("tests", "tsconfig.json");
|
||||
const testsIndex = getTsBuildProjectFile("tests", "index.ts");
|
||||
const baseline: string[] = [];
|
||||
let oldSnap: ReturnType<ts.TestFSWithWatch.TestServerHost["snap"]> | undefined;
|
||||
const system = ts.TestFSWithWatch.changeToHostTrackingWrittenFiles(
|
||||
let oldSnap: ReturnType<TestServerHost["snap"]> | undefined;
|
||||
const system = changeToHostTrackingWrittenFiles(
|
||||
fakes.patchHostForBuildInfoReadWrite(
|
||||
ts.tscWatch.createWatchedSystem([
|
||||
createWatchedSystem([
|
||||
coreConfig, coreIndex, coreDecl, coreAnotherModule,
|
||||
logicConfig, logicIndex,
|
||||
testsConfig, testsIndex,
|
||||
ts.tscWatch.libFile
|
||||
libFile
|
||||
])
|
||||
)
|
||||
);
|
||||
|
||||
const host = ts.createSolutionBuilderHostForBaseline(system);
|
||||
const host = createSolutionBuilderHostForBaseline(system);
|
||||
const builder = ts.createSolutionBuilder(host, [testsConfig.path], { dry: false, force: false, verbose: false });
|
||||
builder.build();
|
||||
baselineState("Build of project");
|
||||
@@ -409,36 +411,36 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => {
|
||||
});
|
||||
});
|
||||
|
||||
const coreChanges: ts.TestTscEdit[] = [
|
||||
const coreChanges: TestTscEdit[] = [
|
||||
{
|
||||
subScenario: "incremental-declaration-changes",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/core/index.ts", `
|
||||
modifyFs: fs => appendText(fs, "/src/core/index.ts", `
|
||||
export class someClass { }`),
|
||||
},
|
||||
{
|
||||
subScenario: "incremental-declaration-doesnt-change",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/core/index.ts", `
|
||||
modifyFs: fs => appendText(fs, "/src/core/index.ts", `
|
||||
class someClass2 { }`),
|
||||
},
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
];
|
||||
|
||||
describe("lists files", () => {
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "sample1",
|
||||
subScenario: "listFiles",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "/src/tests", "--listFiles"],
|
||||
edits: coreChanges
|
||||
});
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "sample1",
|
||||
subScenario: "listEmittedFiles",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "/src/tests", "--listEmittedFiles"],
|
||||
edits: coreChanges
|
||||
});
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "sample1",
|
||||
subScenario: "explainFiles",
|
||||
fs: () => projFs,
|
||||
@@ -448,7 +450,7 @@ class someClass2 { }`),
|
||||
});
|
||||
|
||||
describe("emit output", () => {
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
subScenario: "sample",
|
||||
fs: () => projFs,
|
||||
scenario: "sample1",
|
||||
@@ -459,25 +461,25 @@ class someClass2 { }`),
|
||||
...coreChanges,
|
||||
{
|
||||
subScenario: "when logic config changes declaration dir",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/logic/tsconfig.json", `"declaration": true,`, `"declaration": true,
|
||||
modifyFs: fs => replaceText(fs, "/src/logic/tsconfig.json", `"declaration": true,`, `"declaration": true,
|
||||
"declarationDir": "decls",`),
|
||||
},
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
],
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "sample1",
|
||||
subScenario: "when logic specifies tsBuildInfoFile",
|
||||
fs: () => projFs,
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/logic/tsconfig.json", `"composite": true,`, `"composite": true,
|
||||
modifyFs: fs => replaceText(fs, "/src/logic/tsconfig.json", `"composite": true,`, `"composite": true,
|
||||
"tsBuildInfoFile": "ownFile.tsbuildinfo",`),
|
||||
commandLineArgs: ["--b", "/src/tests", "--verbose"],
|
||||
baselineSourceMap: true,
|
||||
baselineReadFileCalls: true
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
subScenario: "when declaration option changes",
|
||||
fs: () => projFs,
|
||||
scenario: "sample1",
|
||||
@@ -490,11 +492,11 @@ class someClass2 { }`),
|
||||
}`),
|
||||
edits: [{
|
||||
subScenario: "incremental-declaration-changes",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/core/tsconfig.json", `"incremental": true,`, `"incremental": true, "declaration": true,`),
|
||||
modifyFs: fs => replaceText(fs, "/src/core/tsconfig.json", `"incremental": true,`, `"incremental": true, "declaration": true,`),
|
||||
}],
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
subScenario: "when target option changes",
|
||||
fs: () => projFs,
|
||||
scenario: "sample1",
|
||||
@@ -502,7 +504,7 @@ class someClass2 { }`),
|
||||
modifyFs: fs => {
|
||||
fs.writeFileSync("/lib/lib.esnext.full.d.ts", `/// <reference no-default-lib="true"/>
|
||||
/// <reference lib="esnext" />`);
|
||||
fs.writeFileSync("/lib/lib.esnext.d.ts", ts.libContent);
|
||||
fs.writeFileSync("/lib/lib.esnext.d.ts", libContent);
|
||||
fs.writeFileSync("/lib/lib.d.ts", `/// <reference no-default-lib="true"/>
|
||||
/// <reference lib="esnext" />`);
|
||||
fs.writeFileSync("/src/core/tsconfig.json", `{
|
||||
@@ -516,11 +518,11 @@ class someClass2 { }`),
|
||||
},
|
||||
edits: [{
|
||||
subScenario: "incremental-declaration-changes",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/core/tsconfig.json", "esnext", "es5"),
|
||||
modifyFs: fs => replaceText(fs, "/src/core/tsconfig.json", "esnext", "es5"),
|
||||
}],
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
subScenario: "when module option changes",
|
||||
fs: () => projFs,
|
||||
scenario: "sample1",
|
||||
@@ -533,11 +535,11 @@ class someClass2 { }`),
|
||||
}`),
|
||||
edits: [{
|
||||
subScenario: "incremental-declaration-changes",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/core/tsconfig.json", `"module": "commonjs"`, `"module": "amd"`),
|
||||
modifyFs: fs => replaceText(fs, "/src/core/tsconfig.json", `"module": "commonjs"`, `"module": "amd"`),
|
||||
}],
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
subScenario: "when esModuleInterop option changes",
|
||||
fs: () => projFs,
|
||||
scenario: "sample1",
|
||||
@@ -558,11 +560,11 @@ class someClass2 { }`),
|
||||
}`),
|
||||
edits: [{
|
||||
subScenario: "incremental-declaration-changes",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/tests/tsconfig.json", `"esModuleInterop": false`, `"esModuleInterop": true`),
|
||||
modifyFs: fs => replaceText(fs, "/src/tests/tsconfig.json", `"esModuleInterop": false`, `"esModuleInterop": true`),
|
||||
}],
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "sample1",
|
||||
subScenario: "reports error if input file is missing",
|
||||
fs: () => projFs,
|
||||
@@ -576,7 +578,7 @@ class someClass2 { }`),
|
||||
}
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "sample1",
|
||||
subScenario: "reports error if input file is missing with force",
|
||||
fs: () => projFs,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as vfs from "../../_namespaces/vfs";
|
||||
import { loadProjectFromDisk, verifyTsc } from "../tsc/helpers";
|
||||
|
||||
describe("unittests:: tsbuild:: when project reference is referenced transitively", () => {
|
||||
let projFs: vfs.FileSystem;
|
||||
before(() => {
|
||||
projFs = ts.loadProjectFromDisk("tests/projects/transitiveReferences");
|
||||
projFs = loadProjectFromDisk("tests/projects/transitiveReferences");
|
||||
});
|
||||
after(() => {
|
||||
projFs = undefined!; // Release the contents
|
||||
@@ -23,14 +23,14 @@ export const b = new A();`);
|
||||
}));
|
||||
}
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "transitiveReferences",
|
||||
subScenario: "builds correctly",
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--b", "/src/tsconfig.c.json", "--listFiles"],
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "transitiveReferences",
|
||||
subScenario: "builds correctly when the referenced project uses different module resolution",
|
||||
fs: () => projFs,
|
||||
@@ -38,7 +38,7 @@ export const b = new A();`);
|
||||
modifyFs: fs => modifyFsBTsToNonRelativeImport(fs, "classic"),
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "transitiveReferences",
|
||||
subScenario: "reports error about module not found with node resolution with external module name",
|
||||
fs: () => projFs,
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as Utils from "../../_namespaces/Utils";
|
||||
import { createWatchedSystem, libFile, TestServerHost } from "../virtualFileSystemWithWatch";
|
||||
import { verifyTscWatch } from "../tscWatch/helpers";
|
||||
import { dedent } from "../../_namespaces/Utils";
|
||||
|
||||
describe("unittests:: tsbuildWatch:: watchMode:: configFileErrors:: reports syntax errors in config file", () => {
|
||||
function build(sys: ts.tscWatch.WatchedSystem) {
|
||||
function build(sys: TestServerHost) {
|
||||
sys.checkTimeoutQueueLengthAndRun(1); // build the project
|
||||
sys.checkTimeoutQueueLength(0);
|
||||
}
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "configFileErrors",
|
||||
subScenario: "reports syntax errors in config file",
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
sys: () => createWatchedSystem(
|
||||
[
|
||||
{ path: `${ts.tscWatch.projectRoot}/a.ts`, content: "export function foo() { }" },
|
||||
{ path: `${ts.tscWatch.projectRoot}/b.ts`, content: "export function bar() { }" },
|
||||
{ path: `/user/username/projects/myproject/a.ts`, content: "export function foo() { }" },
|
||||
{ path: `/user/username/projects/myproject/b.ts`, content: "export function bar() { }" },
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
content: Utils.dedent`
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: dedent`
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
@@ -26,31 +27,31 @@ describe("unittests:: tsbuildWatch:: watchMode:: configFileErrors:: reports synt
|
||||
]
|
||||
}`
|
||||
},
|
||||
ts.tscWatch.libFile
|
||||
libFile
|
||||
],
|
||||
{ currentDirectory: ts.tscWatch.projectRoot }
|
||||
{ currentDirectory: "/user/username/projects/myproject" }
|
||||
),
|
||||
commandLineArgs: ["--b", "-w"],
|
||||
changes: [
|
||||
{
|
||||
caption: "reports syntax errors after change to config file",
|
||||
change: sys => ts.tscWatch.replaceFileText(sys, `${ts.tscWatch.projectRoot}/tsconfig.json`, ",", `,
|
||||
change: sys => sys.replaceFileText(`/user/username/projects/myproject/tsconfig.json`, ",", `,
|
||||
"declaration": true,`),
|
||||
timeouts: build,
|
||||
},
|
||||
{
|
||||
caption: "reports syntax errors after change to ts file",
|
||||
change: sys => ts.tscWatch.replaceFileText(sys, `${ts.tscWatch.projectRoot}/a.ts`, "foo", "fooBar"),
|
||||
change: sys => sys.replaceFileText(`/user/username/projects/myproject/a.ts`, "foo", "fooBar"),
|
||||
timeouts: build,
|
||||
},
|
||||
{
|
||||
caption: "reports error when there is no change to tsconfig file",
|
||||
change: sys => ts.tscWatch.replaceFileText(sys, `${ts.tscWatch.projectRoot}/tsconfig.json`, "", ""),
|
||||
change: sys => sys.replaceFileText(`/user/username/projects/myproject/tsconfig.json`, "", ""),
|
||||
timeouts: build,
|
||||
},
|
||||
{
|
||||
caption: "builds after fixing config file errors",
|
||||
change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/tsconfig.json`, JSON.stringify({
|
||||
change: sys => sys.writeFile(`/user/username/projects/myproject/tsconfig.json`, JSON.stringify({
|
||||
compilerOptions: { composite: true, declaration: true },
|
||||
files: ["a.ts", "b.ts"]
|
||||
})),
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { createWatchedSystem, File, getTsBuildProjectFile, libFile } from "../virtualFileSystemWithWatch";
|
||||
import { libContent } from "../tsc/helpers";
|
||||
import { verifyTscWatch } from "../tscWatch/helpers";
|
||||
|
||||
describe("unittests:: tsbuildWatch:: watchMode:: with demo project", () => {
|
||||
const projectLocation = `${ts.TestFSWithWatch.tsbuildProjectsLocation}/demo`;
|
||||
let coreFiles: ts.tscWatch.File[];
|
||||
let animalFiles: ts.tscWatch.File[];
|
||||
let zooFiles: ts.tscWatch.File[];
|
||||
let solutionFile: ts.tscWatch.File;
|
||||
let baseConfig: ts.tscWatch.File;
|
||||
let allFiles: ts.tscWatch.File[];
|
||||
const projectLocation = `/user/username/projects/demo`;
|
||||
let coreFiles: File[];
|
||||
let animalFiles: File[];
|
||||
let zooFiles: File[];
|
||||
let solutionFile: File;
|
||||
let baseConfig: File;
|
||||
let allFiles: File[];
|
||||
before(() => {
|
||||
coreFiles = subProjectFiles("core", ["tsconfig.json", "utilities.ts"]);
|
||||
animalFiles = subProjectFiles("animals", ["tsconfig.json", "animal.ts", "dog.ts", "index.ts"]);
|
||||
zooFiles = subProjectFiles("zoo", ["tsconfig.json", "zoo.ts"]);
|
||||
solutionFile = projectFile("tsconfig.json");
|
||||
baseConfig = projectFile("tsconfig-base.json");
|
||||
allFiles = [...coreFiles, ...animalFiles, ...zooFiles, solutionFile, baseConfig, { path: ts.tscWatch.libFile.path, content: ts.libContent }];
|
||||
allFiles = [...coreFiles, ...animalFiles, ...zooFiles, solutionFile, baseConfig, { path: libFile.path, content: libContent }];
|
||||
});
|
||||
|
||||
after(() => {
|
||||
@@ -26,12 +28,12 @@ describe("unittests:: tsbuildWatch:: watchMode:: with demo project", () => {
|
||||
allFiles = undefined!;
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "demo",
|
||||
subScenario: "updates with circular reference",
|
||||
commandLineArgs: ["-b", "-w", "-verbose"],
|
||||
sys: () => {
|
||||
const sys = ts.tscWatch.createWatchedSystem(allFiles, { currentDirectory: projectLocation });
|
||||
const sys = createWatchedSystem(allFiles, { currentDirectory: projectLocation });
|
||||
sys.writeFile(coreFiles[0].path, coreFiles[0].content.replace(
|
||||
"}",
|
||||
`},
|
||||
@@ -56,12 +58,12 @@ describe("unittests:: tsbuildWatch:: watchMode:: with demo project", () => {
|
||||
]
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "demo",
|
||||
subScenario: "updates with bad reference",
|
||||
commandLineArgs: ["-b", "-w", "-verbose"],
|
||||
sys: () => {
|
||||
const sys = ts.tscWatch.createWatchedSystem(allFiles, { currentDirectory: projectLocation });
|
||||
const sys = createWatchedSystem(allFiles, { currentDirectory: projectLocation });
|
||||
sys.writeFile(coreFiles[1].path, `import * as A from '../animals';
|
||||
${coreFiles[1].content}`);
|
||||
return sys;
|
||||
@@ -73,16 +75,19 @@ ${coreFiles[1].content}`);
|
||||
import * as A from '../animals';
|
||||
${coreFiles[1].content}`),
|
||||
// build core
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout,
|
||||
timeouts: sys => {
|
||||
sys.checkTimeoutQueueLengthAndRun(1);
|
||||
sys.checkTimeoutQueueLength(0);
|
||||
},
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
function subProjectFiles(subProject: string, fileNames: readonly string[]): ts.tscWatch.File[] {
|
||||
function subProjectFiles(subProject: string, fileNames: readonly string[]): File[] {
|
||||
return fileNames.map(file => projectFile(`${subProject}/${file}`));
|
||||
}
|
||||
|
||||
function projectFile(fileName: string): ts.tscWatch.File {
|
||||
return ts.TestFSWithWatch.getTsBuildProjectFile("demo", fileName);
|
||||
function projectFile(fileName: string): File {
|
||||
return getTsBuildProjectFile("demo", fileName);
|
||||
}
|
||||
});
|
||||
@@ -1,34 +1,35 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as Utils from "../../_namespaces/Utils";
|
||||
import { createWatchedSystem, libFile } from "../virtualFileSystemWithWatch";
|
||||
import { verifyTscWatch } from "../tscWatch/helpers";
|
||||
import { dedent } from "../../_namespaces/Utils";
|
||||
|
||||
describe("unittests:: tsbuildWatch:: watchMode:: moduleResolution", () => {
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "moduleResolutionCache",
|
||||
subScenario: "handles the cache correctly when two projects use different module resolution settings",
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
sys: () => createWatchedSystem(
|
||||
[
|
||||
{ path: `${ts.tscWatch.projectRoot}/project1/index.ts`, content: `import { foo } from "file";` },
|
||||
{ path: `${ts.tscWatch.projectRoot}/project1/node_modules/file/index.d.ts`, content: "export const foo = 10;" },
|
||||
{ path: `/user/username/projects/myproject/project1/index.ts`, content: `import { foo } from "file";` },
|
||||
{ path: `/user/username/projects/myproject/project1/node_modules/file/index.d.ts`, content: "export const foo = 10;" },
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/project1/tsconfig.json`,
|
||||
path: `/user/username/projects/myproject/project1/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { composite: true, types: ["foo", "bar"] },
|
||||
files: ["index.ts"]
|
||||
})
|
||||
},
|
||||
{ path: `${ts.tscWatch.projectRoot}/project2/index.ts`, content: `import { foo } from "file";` },
|
||||
{ path: `${ts.tscWatch.projectRoot}/project2/file.d.ts`, content: "export const foo = 10;" },
|
||||
{ path: `/user/username/projects/myproject/project2/index.ts`, content: `import { foo } from "file";` },
|
||||
{ path: `/user/username/projects/myproject/project2/file.d.ts`, content: "export const foo = 10;" },
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/project2/tsconfig.json`,
|
||||
path: `/user/username/projects/myproject/project2/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { composite: true, types: ["foo"], moduleResolution: "classic" },
|
||||
files: ["index.ts"]
|
||||
})
|
||||
},
|
||||
{ path: `${ts.tscWatch.projectRoot}/node_modules/@types/foo/index.d.ts`, content: "export const foo = 10;" },
|
||||
{ path: `${ts.tscWatch.projectRoot}/node_modules/@types/bar/index.d.ts`, content: "export const bar = 10;" },
|
||||
{ path: `/user/username/projects/myproject/node_modules/@types/foo/index.d.ts`, content: "export const foo = 10;" },
|
||||
{ path: `/user/username/projects/myproject/node_modules/@types/bar/index.d.ts`, content: "export const bar = 10;" },
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
files: [],
|
||||
references: [
|
||||
@@ -37,15 +38,15 @@ describe("unittests:: tsbuildWatch:: watchMode:: moduleResolution", () => {
|
||||
]
|
||||
})
|
||||
},
|
||||
ts.tscWatch.libFile
|
||||
libFile
|
||||
],
|
||||
{ currentDirectory: ts.tscWatch.projectRoot }
|
||||
{ currentDirectory: "/user/username/projects/myproject" }
|
||||
),
|
||||
commandLineArgs: ["--b", "-w", "-v"],
|
||||
changes: [
|
||||
{
|
||||
caption: "Append text",
|
||||
change: sys => sys.appendFile(`${ts.tscWatch.projectRoot}/project1/index.ts`, "const bar = 10;"),
|
||||
change: sys => sys.appendFile(`/user/username/projects/myproject/project1/index.ts`, "const bar = 10;"),
|
||||
timeouts: sys => {
|
||||
sys.checkTimeoutQueueLengthAndRun(1); // build project1 and solution
|
||||
sys.checkTimeoutQueueLength(0);
|
||||
@@ -54,12 +55,12 @@ describe("unittests:: tsbuildWatch:: watchMode:: moduleResolution", () => {
|
||||
]
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "moduleResolution",
|
||||
subScenario: `resolves specifier in output declaration file from referenced project correctly with cts and mts extensions`,
|
||||
sys: () => ts.tscWatch.createWatchedSystem([
|
||||
sys: () => createWatchedSystem([
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/packages/pkg1/package.json`,
|
||||
path: `/user/username/projects/myproject/packages/pkg1/package.json`,
|
||||
content: JSON.stringify({
|
||||
name: "pkg1",
|
||||
version: "1.0.0",
|
||||
@@ -68,13 +69,13 @@ describe("unittests:: tsbuildWatch:: watchMode:: moduleResolution", () => {
|
||||
})
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/packages/pkg1/index.ts`,
|
||||
content: Utils.dedent`
|
||||
path: `/user/username/projects/myproject/packages/pkg1/index.ts`,
|
||||
content: dedent`
|
||||
import type { TheNum } from 'pkg2'
|
||||
export const theNum: TheNum = 42;`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/packages/pkg1/tsconfig.json`,
|
||||
path: `/user/username/projects/myproject/packages/pkg1/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
outDir: "build",
|
||||
@@ -84,15 +85,15 @@ describe("unittests:: tsbuildWatch:: watchMode:: moduleResolution", () => {
|
||||
})
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/packages/pkg2/const.cts`,
|
||||
path: `/user/username/projects/myproject/packages/pkg2/const.cts`,
|
||||
content: `export type TheNum = 42;`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/packages/pkg2/index.ts`,
|
||||
path: `/user/username/projects/myproject/packages/pkg2/index.ts`,
|
||||
content: `export type { TheNum } from './const.cjs';`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/packages/pkg2/tsconfig.json`,
|
||||
path: `/user/username/projects/myproject/packages/pkg2/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
composite: true,
|
||||
@@ -102,7 +103,7 @@ describe("unittests:: tsbuildWatch:: watchMode:: moduleResolution", () => {
|
||||
})
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/packages/pkg2/package.json`,
|
||||
path: `/user/username/projects/myproject/packages/pkg2/package.json`,
|
||||
content: JSON.stringify({
|
||||
name: "pkg2",
|
||||
version: "1.0.0",
|
||||
@@ -111,33 +112,33 @@ describe("unittests:: tsbuildWatch:: watchMode:: moduleResolution", () => {
|
||||
})
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/pkg2`,
|
||||
symLink: `${ts.tscWatch.projectRoot}/packages/pkg2`,
|
||||
path: `/user/username/projects/myproject/node_modules/pkg2`,
|
||||
symLink: `/user/username/projects/myproject/packages/pkg2`,
|
||||
},
|
||||
{ ...ts.tscWatch.libFile, path: `/a/lib/lib.es2022.full.d.ts` }
|
||||
], { currentDirectory: ts.tscWatch.projectRoot }),
|
||||
{ ...libFile, path: `/a/lib/lib.es2022.full.d.ts` }
|
||||
], { currentDirectory: "/user/username/projects/myproject" }),
|
||||
commandLineArgs: ["-b", "packages/pkg1", "-w", "--verbose", "--traceResolution"],
|
||||
changes: [
|
||||
{
|
||||
caption: "reports import errors after change to package file",
|
||||
change: sys => ts.tscWatch.replaceFileText(sys, `${ts.tscWatch.projectRoot}/packages/pkg1/package.json`, `"module"`, `"commonjs"`),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks
|
||||
change: sys => sys.replaceFileText(`/user/username/projects/myproject/packages/pkg1/package.json`, `"module"`, `"commonjs"`),
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
},
|
||||
{
|
||||
caption: "removes those errors when a package file is changed back",
|
||||
change: sys => ts.tscWatch.replaceFileText(sys, `${ts.tscWatch.projectRoot}/packages/pkg1/package.json`, `"commonjs"`, `"module"`),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks,
|
||||
change: sys => sys.replaceFileText(`/user/username/projects/myproject/packages/pkg1/package.json`, `"commonjs"`, `"module"`),
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
},
|
||||
{
|
||||
caption: "reports import errors after change to package file",
|
||||
change: sys => ts.tscWatch.replaceFileText(sys, `${ts.tscWatch.projectRoot}/packages/pkg1/package.json`, `"module"`, `"commonjs"`),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks
|
||||
change: sys => sys.replaceFileText(`/user/username/projects/myproject/packages/pkg1/package.json`, `"module"`, `"commonjs"`),
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks()
|
||||
},
|
||||
{
|
||||
caption: "removes those errors when a package file is changed to cjs extensions",
|
||||
change: sys => {
|
||||
ts.tscWatch.replaceFileText(sys, `${ts.tscWatch.projectRoot}/packages/pkg2/package.json`, `"build/index.js"`, `"build/index.cjs"`);
|
||||
sys.renameFile(`${ts.tscWatch.projectRoot}/packages/pkg2/index.ts`, `${ts.tscWatch.projectRoot}/packages/pkg2/index.cts`);
|
||||
sys.replaceFileText(`/user/username/projects/myproject/packages/pkg2/package.json`, `"build/index.js"`, `"build/index.cjs"`);
|
||||
sys.renameFile(`/user/username/projects/myproject/packages/pkg2/index.ts`, `/user/username/projects/myproject/packages/pkg2/index.cts`);
|
||||
},
|
||||
timeouts: sys => {
|
||||
sys.runQueuedTimeoutCallbacks(); // building pkg2
|
||||
@@ -147,12 +148,12 @@ describe("unittests:: tsbuildWatch:: watchMode:: moduleResolution", () => {
|
||||
]
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "moduleResolution",
|
||||
subScenario: `build mode watches for changes to package-json main fields`,
|
||||
sys: () => ts.tscWatch.createWatchedSystem([
|
||||
sys: () => createWatchedSystem([
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/packages/pkg1/package.json`,
|
||||
path: `/user/username/projects/myproject/packages/pkg1/package.json`,
|
||||
content: JSON.stringify({
|
||||
name: "pkg1",
|
||||
version: "1.0.0",
|
||||
@@ -160,13 +161,13 @@ describe("unittests:: tsbuildWatch:: watchMode:: moduleResolution", () => {
|
||||
})
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/packages/pkg1/index.ts`,
|
||||
content: Utils.dedent`
|
||||
path: `/user/username/projects/myproject/packages/pkg1/index.ts`,
|
||||
content: dedent`
|
||||
import type { TheNum } from 'pkg2'
|
||||
export const theNum: TheNum = 42;`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/packages/pkg1/tsconfig.json`,
|
||||
path: `/user/username/projects/myproject/packages/pkg1/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
outDir: "build",
|
||||
@@ -175,7 +176,7 @@ describe("unittests:: tsbuildWatch:: watchMode:: moduleResolution", () => {
|
||||
})
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/packages/pkg2/tsconfig.json`,
|
||||
path: `/user/username/projects/myproject/packages/pkg2/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
composite: true,
|
||||
@@ -185,19 +186,19 @@ describe("unittests:: tsbuildWatch:: watchMode:: moduleResolution", () => {
|
||||
})
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/packages/pkg2/const.ts`,
|
||||
path: `/user/username/projects/myproject/packages/pkg2/const.ts`,
|
||||
content: `export type TheNum = 42;`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/packages/pkg2/index.ts`,
|
||||
path: `/user/username/projects/myproject/packages/pkg2/index.ts`,
|
||||
content: `export type { TheNum } from './const.js';`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/packages/pkg2/other.ts`,
|
||||
path: `/user/username/projects/myproject/packages/pkg2/other.ts`,
|
||||
content: `export type TheStr = string;`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/packages/pkg2/package.json`,
|
||||
path: `/user/username/projects/myproject/packages/pkg2/package.json`,
|
||||
content: JSON.stringify({
|
||||
name: "pkg2",
|
||||
version: "1.0.0",
|
||||
@@ -205,22 +206,22 @@ describe("unittests:: tsbuildWatch:: watchMode:: moduleResolution", () => {
|
||||
})
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/pkg2`,
|
||||
symLink: `${ts.tscWatch.projectRoot}/packages/pkg2`,
|
||||
path: `/user/username/projects/myproject/node_modules/pkg2`,
|
||||
symLink: `/user/username/projects/myproject/packages/pkg2`,
|
||||
},
|
||||
ts.tscWatch.libFile
|
||||
], { currentDirectory: ts.tscWatch.projectRoot }),
|
||||
libFile
|
||||
], { currentDirectory: "/user/username/projects/myproject" }),
|
||||
commandLineArgs: ["-b", "packages/pkg1", "--verbose", "-w", "--traceResolution"],
|
||||
changes: [
|
||||
{
|
||||
caption: "reports import errors after change to package file",
|
||||
change: sys => ts.tscWatch.replaceFileText(sys, `${ts.tscWatch.projectRoot}/packages/pkg2/package.json`, `index.js`, `other.js`),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks,
|
||||
change: sys => sys.replaceFileText(`/user/username/projects/myproject/packages/pkg2/package.json`, `index.js`, `other.js`),
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
},
|
||||
{
|
||||
caption: "removes those errors when a package file is changed back",
|
||||
change: sys => ts.tscWatch.replaceFileText(sys, `${ts.tscWatch.projectRoot}/packages/pkg2/package.json`, `other.js`, `index.js`),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks,
|
||||
change: sys => sys.replaceFileText(`/user/username/projects/myproject/packages/pkg2/package.json`, `other.js`, `index.js`),
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
},
|
||||
]
|
||||
});
|
||||
|
||||
@@ -1,31 +1,39 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { createWatchedSystem, libFile } from "../virtualFileSystemWithWatch";
|
||||
import { libContent } from "../tsc/helpers";
|
||||
import { verifyTscWatch } from "../tscWatch/helpers";
|
||||
|
||||
describe("unittests:: tsbuildWatch:: watchMode:: with noEmit", () => {
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "noEmit",
|
||||
subScenario: "does not go in loop when watching when no files are emitted",
|
||||
commandLineArgs: ["-b", "-w", "-verbose"],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
sys: () => createWatchedSystem(
|
||||
[
|
||||
{ path: ts.tscWatch.libFile.path, content: ts.libContent },
|
||||
{ path: `${ts.tscWatch.projectRoot}/a.js`, content: "" },
|
||||
{ path: `${ts.tscWatch.projectRoot}/b.ts`, content: "" },
|
||||
{ path: `${ts.tscWatch.projectRoot}/tsconfig.json`, content: JSON.stringify({ compilerOptions: { allowJs: true, noEmit: true } }) },
|
||||
{ path: libFile.path, content: libContent },
|
||||
{ path: `/user/username/projects/myproject/a.js`, content: "" },
|
||||
{ path: `/user/username/projects/myproject/b.ts`, content: "" },
|
||||
{ path: `/user/username/projects/myproject/tsconfig.json`, content: JSON.stringify({ compilerOptions: { allowJs: true, noEmit: true } }) },
|
||||
],
|
||||
{ currentDirectory: ts.tscWatch.projectRoot }
|
||||
{ currentDirectory: "/user/username/projects/myproject" }
|
||||
),
|
||||
changes: [
|
||||
{
|
||||
caption: "No change",
|
||||
change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/a.js`, sys.readFile(`${ts.tscWatch.projectRoot}/a.js`)!),
|
||||
change: sys => sys.writeFile(`/user/username/projects/myproject/a.js`, sys.readFile(`/user/username/projects/myproject/a.js`)!),
|
||||
// build project
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout,
|
||||
timeouts: sys => {
|
||||
sys.checkTimeoutQueueLengthAndRun(1);
|
||||
sys.checkTimeoutQueueLength(0);
|
||||
},
|
||||
},
|
||||
{
|
||||
caption: "change",
|
||||
change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/a.js`, "const x = 10;"),
|
||||
change: sys => sys.writeFile(`/user/username/projects/myproject/a.js`, "const x = 10;"),
|
||||
// build project
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout,
|
||||
timeouts: sys => {
|
||||
sys.checkTimeoutQueueLengthAndRun(1);
|
||||
sys.checkTimeoutQueueLength(0);
|
||||
},
|
||||
},
|
||||
],
|
||||
baselineIncremental: true
|
||||
|
||||
@@ -1,32 +1,40 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { createWatchedSystem, getTsBuildProjectFile, libFile } from "../virtualFileSystemWithWatch";
|
||||
import { libContent } from "../tsc/helpers";
|
||||
import { TscWatchCompileChange, verifyTscWatch } from "../tscWatch/helpers";
|
||||
|
||||
describe("unittests:: tsbuildWatch:: watchMode:: with noEmitOnError", () => {
|
||||
function change(caption: string, content: string): ts.tscWatch.TscWatchCompileChange {
|
||||
function change(caption: string, content: string): TscWatchCompileChange {
|
||||
return {
|
||||
caption,
|
||||
change: sys => sys.writeFile(`${ts.TestFSWithWatch.tsbuildProjectsLocation}/noEmitOnError/src/main.ts`, content),
|
||||
change: sys => sys.writeFile(`/user/username/projects/noEmitOnError/src/main.ts`, content),
|
||||
// build project
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout,
|
||||
timeouts: sys => {
|
||||
sys.checkTimeoutQueueLengthAndRun(1);
|
||||
sys.checkTimeoutQueueLength(0);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const noChange: ts.tscWatch.TscWatchCompileChange = {
|
||||
const noChange: TscWatchCompileChange = {
|
||||
caption: "No change",
|
||||
change: sys => sys.writeFile(`${ts.TestFSWithWatch.tsbuildProjectsLocation}/noEmitOnError/src/main.ts`, sys.readFile(`${ts.TestFSWithWatch.tsbuildProjectsLocation}/noEmitOnError/src/main.ts`)!),
|
||||
change: sys => sys.writeFile(`/user/username/projects/noEmitOnError/src/main.ts`, sys.readFile(`/user/username/projects/noEmitOnError/src/main.ts`)!),
|
||||
// build project
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout,
|
||||
timeouts: sys => {
|
||||
sys.checkTimeoutQueueLengthAndRun(1);
|
||||
sys.checkTimeoutQueueLength(0);
|
||||
},
|
||||
};
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "noEmitOnError",
|
||||
subScenario: "does not emit any files on error",
|
||||
commandLineArgs: ["-b", "-w", "-verbose"],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
sys: () => createWatchedSystem(
|
||||
[
|
||||
...["tsconfig.json", "shared/types/db.ts", "src/main.ts", "src/other.ts"]
|
||||
.map(f => ts.TestFSWithWatch.getTsBuildProjectFile("noEmitOnError", f)),
|
||||
{ path: ts.tscWatch.libFile.path, content: ts.libContent }
|
||||
.map(f => getTsBuildProjectFile("noEmitOnError", f)),
|
||||
{ path: libFile.path, content: libContent }
|
||||
],
|
||||
{ currentDirectory: `${ts.TestFSWithWatch.tsbuildProjectsLocation}/noEmitOnError` }
|
||||
{ currentDirectory: `/user/username/projects/noEmitOnError` }
|
||||
),
|
||||
changes: [
|
||||
noChange,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
|
||||
import projectsLocation = ts.TestFSWithWatch.tsbuildProjectsLocation;
|
||||
import { createWatchedSystem, File, getTsBuildProjectFile, getTsBuildProjectFilePath, libFile, TestServerHost } from "../virtualFileSystemWithWatch";
|
||||
import { commonFile1, commonFile2, createBaseline, createSolutionBuilderWithWatchHostForBaseline, noopChange, runWatchBaseline, TscWatchCompileChange, verifyTscWatch } from "../tscWatch/helpers";
|
||||
describe("unittests:: tsbuildWatch:: watchMode:: program updates", () => {
|
||||
const enum SubProject {
|
||||
core = "core",
|
||||
@@ -8,15 +8,15 @@ describe("unittests:: tsbuildWatch:: watchMode:: program updates", () => {
|
||||
tests = "tests",
|
||||
ui = "ui"
|
||||
}
|
||||
type ReadonlyFile = Readonly<ts.tscWatch.File>;
|
||||
type ReadonlyFile = Readonly<File>;
|
||||
/** [tsconfig, index] | [tsconfig, index, anotherModule, someDecl] */
|
||||
type SubProjectFiles = [tsconfig: ReadonlyFile, index: ReadonlyFile] | [tsconfig: ReadonlyFile, index: ReadonlyFile, anotherModule: ReadonlyFile, someDecl: ReadonlyFile];
|
||||
function projectFilePath(subProject: SubProject, baseFileName: string) {
|
||||
return `${ts.TestFSWithWatch.getTsBuildProjectFilePath("sample1", subProject)}/${baseFileName.toLowerCase()}`;
|
||||
return `${getTsBuildProjectFilePath("sample1", subProject)}/${baseFileName.toLowerCase()}`;
|
||||
}
|
||||
|
||||
function projectFile(subProject: SubProject, baseFileName: string): ts.tscWatch.File {
|
||||
return ts.TestFSWithWatch.getTsBuildProjectFile("sample1", `${subProject}/${baseFileName}`);
|
||||
function projectFile(subProject: SubProject, baseFileName: string): File {
|
||||
return getTsBuildProjectFile("sample1", `${subProject}/${baseFileName}`);
|
||||
}
|
||||
|
||||
function subProjectFiles(subProject: SubProject, anotherModuleAndSomeDecl?: true): SubProjectFiles {
|
||||
@@ -30,11 +30,11 @@ describe("unittests:: tsbuildWatch:: watchMode:: program updates", () => {
|
||||
return [tsconfig, index, anotherModule, someDecl];
|
||||
}
|
||||
|
||||
function changeFile(fileName: string | (() => string), content: string | (() => string), caption: string): ts.tscWatch.TscWatchCompileChange {
|
||||
function changeFile(fileName: string | (() => string), content: string | (() => string), caption: string): TscWatchCompileChange {
|
||||
return {
|
||||
caption,
|
||||
change: sys => sys.writeFile(ts.isString(fileName) ? fileName : fileName(), ts.isString(content) ? content : content()),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, // Builds core
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), // Builds core
|
||||
};
|
||||
}
|
||||
|
||||
@@ -46,14 +46,14 @@ describe("unittests:: tsbuildWatch:: watchMode:: program updates", () => {
|
||||
let logic: SubProjectFiles;
|
||||
let tests: SubProjectFiles;
|
||||
let ui: SubProjectFiles;
|
||||
let allFiles: readonly ts.tscWatch.File[];
|
||||
let allFiles: readonly File[];
|
||||
|
||||
before(() => {
|
||||
core = subProjectFiles(SubProject.core, /*anotherModuleAndSomeDecl*/ true);
|
||||
logic = subProjectFiles(SubProject.logic);
|
||||
tests = subProjectFiles(SubProject.tests);
|
||||
ui = subProjectFiles(SubProject.ui);
|
||||
allFiles = [ts.tscWatch.libFile, ...core, ...logic, ...tests, ...ui];
|
||||
allFiles = [libFile, ...core, ...logic, ...tests, ...ui];
|
||||
});
|
||||
|
||||
after(() => {
|
||||
@@ -64,20 +64,20 @@ describe("unittests:: tsbuildWatch:: watchMode:: program updates", () => {
|
||||
allFiles = undefined!;
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "programUpdates",
|
||||
subScenario: "creates solution in watch mode",
|
||||
commandLineArgs: ["-b", "-w", `sample1/${SubProject.tests}`],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(allFiles, { currentDirectory: projectsLocation }),
|
||||
sys: () => createWatchedSystem(allFiles, { currentDirectory: "/user/username/projects" }),
|
||||
changes: ts.emptyArray
|
||||
});
|
||||
|
||||
it("verify building references watches only those projects", () => {
|
||||
const { sys, baseline, oldSnap, cb, getPrograms } = ts.tscWatch.createBaseline(ts.tscWatch.createWatchedSystem(allFiles, { currentDirectory: projectsLocation }));
|
||||
const host = ts.tscWatch.createSolutionBuilderWithWatchHostForBaseline(sys, cb);
|
||||
const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem(allFiles, { currentDirectory: "/user/username/projects" }));
|
||||
const host = createSolutionBuilderWithWatchHostForBaseline(sys, cb);
|
||||
const solutionBuilder = ts.createSolutionBuilderWithWatch(host, [`sample1/${SubProject.tests}`], { watch: true });
|
||||
solutionBuilder.buildReferences(`sample1/${SubProject.tests}`);
|
||||
ts.tscWatch.runWatchBaseline({
|
||||
runWatchBaseline({
|
||||
scenario: "programUpdates",
|
||||
subScenario: "verify building references watches only those projects",
|
||||
commandLineArgs: ["--b", "--w"],
|
||||
@@ -92,25 +92,28 @@ describe("unittests:: tsbuildWatch:: watchMode:: program updates", () => {
|
||||
|
||||
describe("validates the changes and watched files", () => {
|
||||
const newFileWithoutExtension = "newFile";
|
||||
const newFile: ts.tscWatch.File = {
|
||||
const newFile: File = {
|
||||
path: projectFilePath(SubProject.core, `${newFileWithoutExtension}.ts`),
|
||||
content: `export const newFileConst = 30;`
|
||||
};
|
||||
|
||||
function verifyProjectChanges(subScenario: string, allFilesGetter: () => readonly ts.tscWatch.File[]) {
|
||||
const buildLogicAndTests: ts.tscWatch.TscWatchCompileChange = {
|
||||
function verifyProjectChanges(subScenario: string, allFilesGetter: () => readonly File[]) {
|
||||
const buildLogicAndTests: TscWatchCompileChange = {
|
||||
caption: "Build logic and tests",
|
||||
change: ts.noop,
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout,
|
||||
timeouts: sys => {
|
||||
sys.checkTimeoutQueueLengthAndRun(1);
|
||||
sys.checkTimeoutQueueLength(0);
|
||||
},
|
||||
};
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "programUpdates",
|
||||
subScenario: `${subScenario}/change builds changes and reports found errors message`,
|
||||
commandLineArgs: ["-b", "-w", `sample1/${SubProject.tests}`],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
sys: () => createWatchedSystem(
|
||||
allFilesGetter(),
|
||||
{ currentDirectory: projectsLocation }
|
||||
{ currentDirectory: "/user/username/projects" }
|
||||
),
|
||||
changes: [
|
||||
changeCore(() => `${core[1].content}
|
||||
@@ -130,19 +133,19 @@ export class someClass { }`;
|
||||
sys.writeFile(core[1].path, `${change1}
|
||||
export class someClass2 { }`);
|
||||
},
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, // Builds core
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), // Builds core
|
||||
},
|
||||
buildLogicAndTests,
|
||||
]
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "programUpdates",
|
||||
subScenario: `${subScenario}/non local change does not start build of referencing projects`,
|
||||
commandLineArgs: ["-b", "-w", `sample1/${SubProject.tests}`],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
sys: () => createWatchedSystem(
|
||||
allFilesGetter(),
|
||||
{ currentDirectory: projectsLocation }
|
||||
{ currentDirectory: "/user/username/projects" }
|
||||
),
|
||||
changes: [
|
||||
changeCore(() => `${core[1].content}
|
||||
@@ -153,13 +156,13 @@ function foo() { }`, "Make local change to core"),
|
||||
function changeNewFile(newFileContent: string) {
|
||||
return changeFile(newFile.path, newFileContent, "Change to new File and build core");
|
||||
}
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "programUpdates",
|
||||
subScenario: `${subScenario}/builds when new file is added, and its subsequent updates`,
|
||||
commandLineArgs: ["-b", "-w", `sample1/${SubProject.tests}`],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
sys: () => createWatchedSystem(
|
||||
allFilesGetter(),
|
||||
{ currentDirectory: projectsLocation }
|
||||
{ currentDirectory: "/user/username/projects" }
|
||||
),
|
||||
changes: [
|
||||
changeNewFile(newFile.content),
|
||||
@@ -183,44 +186,47 @@ export class someClass2 { }`),
|
||||
"with circular project reference",
|
||||
() => {
|
||||
const [coreTsconfig, ...otherCoreFiles] = core;
|
||||
const circularCoreConfig: ts.tscWatch.File = {
|
||||
const circularCoreConfig: File = {
|
||||
path: coreTsconfig.path,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { composite: true, declaration: true },
|
||||
references: [{ path: "../tests", circular: true }]
|
||||
})
|
||||
};
|
||||
return [ts.tscWatch.libFile, circularCoreConfig, ...otherCoreFiles, ...logic, ...tests];
|
||||
return [libFile, circularCoreConfig, ...otherCoreFiles, ...logic, ...tests];
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "programUpdates",
|
||||
subScenario: "watches config files that are not present",
|
||||
commandLineArgs: ["-b", "-w", `sample1/${SubProject.tests}`],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
[ts.tscWatch.libFile, ...core, logic[1], ...tests],
|
||||
{ currentDirectory: projectsLocation }
|
||||
sys: () => createWatchedSystem(
|
||||
[libFile, ...core, logic[1], ...tests],
|
||||
{ currentDirectory: "/user/username/projects" }
|
||||
),
|
||||
changes: [
|
||||
{
|
||||
caption: "Write logic tsconfig and build logic",
|
||||
change: sys => sys.writeFile(logic[0].path, logic[0].content),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, // Builds logic
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), // Builds logic
|
||||
},
|
||||
{
|
||||
caption: "Build Tests",
|
||||
change: ts.noop,
|
||||
// Build tests
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout,
|
||||
timeouts: sys => {
|
||||
sys.checkTimeoutQueueLengthAndRun(1);
|
||||
sys.checkTimeoutQueueLength(0);
|
||||
},
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
describe("when referenced using prepend, builds referencing project even for non local change", () => {
|
||||
let coreIndex: ts.tscWatch.File;
|
||||
let coreIndex: File;
|
||||
before(() => {
|
||||
coreIndex = {
|
||||
path: core[1].path,
|
||||
@@ -230,35 +236,38 @@ export class someClass2 { }`),
|
||||
after(() => {
|
||||
coreIndex = undefined!;
|
||||
});
|
||||
const buildLogic: ts.tscWatch.TscWatchCompileChange = {
|
||||
const buildLogic: TscWatchCompileChange = {
|
||||
caption: "Build logic",
|
||||
change: ts.noop,
|
||||
// Builds logic
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout,
|
||||
timeouts: sys => {
|
||||
sys.checkTimeoutQueueLengthAndRun(1);
|
||||
sys.checkTimeoutQueueLength(0);
|
||||
},
|
||||
};
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "programUpdates",
|
||||
subScenario: "when referenced using prepend builds referencing project even for non local change",
|
||||
commandLineArgs: ["-b", "-w", `sample1/${SubProject.logic}`],
|
||||
sys: () => {
|
||||
const coreTsConfig: ts.tscWatch.File = {
|
||||
const coreTsConfig: File = {
|
||||
path: core[0].path,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { composite: true, declaration: true, outFile: "index.js" }
|
||||
})
|
||||
};
|
||||
const logicTsConfig: ts.tscWatch.File = {
|
||||
const logicTsConfig: File = {
|
||||
path: logic[0].path,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { composite: true, declaration: true, outFile: "index.js" },
|
||||
references: [{ path: "../core", prepend: true }]
|
||||
})
|
||||
};
|
||||
const logicIndex: ts.tscWatch.File = {
|
||||
const logicIndex: File = {
|
||||
path: logic[1].path,
|
||||
content: `function bar() { return foo() + 1 };`
|
||||
};
|
||||
return ts.tscWatch.createWatchedSystem([ts.tscWatch.libFile, coreTsConfig, coreIndex, logicTsConfig, logicIndex], { currentDirectory: projectsLocation });
|
||||
return createWatchedSystem([libFile, coreTsConfig, coreIndex, logicTsConfig, logicIndex], { currentDirectory: "/user/username/projects" });
|
||||
},
|
||||
changes: [
|
||||
changeCore(() => `${coreIndex.content}
|
||||
@@ -272,8 +281,8 @@ function myFunc() { return 100; }`, "Make local change and build core"),
|
||||
});
|
||||
|
||||
describe("when referenced project change introduces error in the down stream project and then fixes it", () => {
|
||||
const subProjectLibrary = `${projectsLocation}/sample1/Library`;
|
||||
const libraryTs: ts.tscWatch.File = {
|
||||
const subProjectLibrary = `${"/user/username/projects"}/sample1/Library`;
|
||||
const libraryTs: File = {
|
||||
path: `${subProjectLibrary}/library.ts`,
|
||||
content: `
|
||||
interface SomeObject
|
||||
@@ -288,28 +297,28 @@ export function createSomeObject(): SomeObject
|
||||
};
|
||||
}`
|
||||
};
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "programUpdates",
|
||||
subScenario: "when referenced project change introduces error in the down stream project and then fixes it",
|
||||
commandLineArgs: ["-b", "-w", "App"],
|
||||
sys: () => {
|
||||
const libraryTsconfig: ts.tscWatch.File = {
|
||||
const libraryTsconfig: File = {
|
||||
path: `${subProjectLibrary}/tsconfig.json`,
|
||||
content: JSON.stringify({ compilerOptions: { composite: true } })
|
||||
};
|
||||
const subProjectApp = `${projectsLocation}/sample1/App`;
|
||||
const appTs: ts.tscWatch.File = {
|
||||
const subProjectApp = `${"/user/username/projects"}/sample1/App`;
|
||||
const appTs: File = {
|
||||
path: `${subProjectApp}/app.ts`,
|
||||
content: `import { createSomeObject } from "../Library/library";
|
||||
createSomeObject().message;`
|
||||
};
|
||||
const appTsconfig: ts.tscWatch.File = {
|
||||
const appTsconfig: File = {
|
||||
path: `${subProjectApp}/tsconfig.json`,
|
||||
content: JSON.stringify({ references: [{ path: "../Library" }] })
|
||||
};
|
||||
|
||||
const files = [ts.tscWatch.libFile, libraryTs, libraryTsconfig, appTs, appTsconfig];
|
||||
return ts.tscWatch.createWatchedSystem(files, { currentDirectory: `${projectsLocation}/sample1` });
|
||||
const files = [libFile, libraryTs, libraryTsconfig, appTs, appTsconfig];
|
||||
return createWatchedSystem(files, { currentDirectory: `${"/user/username/projects"}/sample1` });
|
||||
},
|
||||
changes: [
|
||||
{
|
||||
@@ -337,25 +346,31 @@ createSomeObject().message;`
|
||||
|
||||
describe("reports errors in all projects on incremental compile", () => {
|
||||
function verifyIncrementalErrors(subScenario: string, buildOptions: readonly string[]) {
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "programUpdates",
|
||||
subScenario: `reportErrors/${subScenario}`,
|
||||
commandLineArgs: ["-b", "-w", `sample1/${SubProject.tests}`, ...buildOptions],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(allFiles, { currentDirectory: projectsLocation }),
|
||||
sys: () => createWatchedSystem(allFiles, { currentDirectory: "/user/username/projects" }),
|
||||
changes: [
|
||||
{
|
||||
caption: "change logic",
|
||||
change: sys => sys.writeFile(logic[1].path, `${logic[1].content}
|
||||
let y: string = 10;`),
|
||||
// Builds logic
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout,
|
||||
timeouts: sys => {
|
||||
sys.checkTimeoutQueueLengthAndRun(1);
|
||||
sys.checkTimeoutQueueLength(0);
|
||||
},
|
||||
},
|
||||
{
|
||||
caption: "change core",
|
||||
change: sys => sys.writeFile(core[1].path, `${core[1].content}
|
||||
let x: string = 10;`),
|
||||
// Builds core
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout,
|
||||
timeouts: sys => {
|
||||
sys.checkTimeoutQueueLengthAndRun(1);
|
||||
sys.checkTimeoutQueueLength(0);
|
||||
},
|
||||
}
|
||||
]
|
||||
});
|
||||
@@ -366,65 +381,65 @@ let x: string = 10;`),
|
||||
describe("when declaration emit errors are present", () => {
|
||||
const solution = "solution";
|
||||
const subProject = "app";
|
||||
const subProjectLocation = `${projectsLocation}/${solution}/${subProject}`;
|
||||
const fileWithError: ts.tscWatch.File = {
|
||||
const subProjectLocation = `${"/user/username/projects"}/${solution}/${subProject}`;
|
||||
const fileWithError: File = {
|
||||
path: `${subProjectLocation}/fileWithError.ts`,
|
||||
content: `export var myClassWithError = class {
|
||||
tags() { }
|
||||
private p = 12
|
||||
};`
|
||||
};
|
||||
const fileWithFixedError: ts.tscWatch.File = {
|
||||
const fileWithFixedError: File = {
|
||||
path: fileWithError.path,
|
||||
content: fileWithError.content.replace("private p = 12", "")
|
||||
};
|
||||
const fileWithoutError: ts.tscWatch.File = {
|
||||
const fileWithoutError: File = {
|
||||
path: `${subProjectLocation}/fileWithoutError.ts`,
|
||||
content: `export class myClass { }`
|
||||
};
|
||||
const tsconfig: ts.tscWatch.File = {
|
||||
const tsconfig: File = {
|
||||
path: `${subProjectLocation}/tsconfig.json`,
|
||||
content: JSON.stringify({ compilerOptions: { composite: true } })
|
||||
};
|
||||
|
||||
function incrementalBuild(sys: ts.tscWatch.WatchedSystem) {
|
||||
function incrementalBuild(sys: TestServerHost) {
|
||||
sys.checkTimeoutQueueLengthAndRun(1); // Build the app
|
||||
sys.checkTimeoutQueueLength(0);
|
||||
}
|
||||
|
||||
const fixError: ts.tscWatch.TscWatchCompileChange = {
|
||||
const fixError: TscWatchCompileChange = {
|
||||
caption: "Fix error in fileWithError",
|
||||
// Fix error
|
||||
change: sys => sys.writeFile(fileWithError.path, fileWithFixedError.content),
|
||||
timeouts: incrementalBuild
|
||||
};
|
||||
|
||||
const changeFileWithoutError: ts.tscWatch.TscWatchCompileChange = {
|
||||
const changeFileWithoutError: TscWatchCompileChange = {
|
||||
caption: "Change fileWithoutError",
|
||||
change: sys => sys.writeFile(fileWithoutError.path, fileWithoutError.content.replace(/myClass/g, "myClass2")),
|
||||
timeouts: incrementalBuild
|
||||
};
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "programUpdates",
|
||||
subScenario: "reportErrors/declarationEmitErrors/when fixing error files all files are emitted",
|
||||
commandLineArgs: ["-b", "-w", subProject],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
[ts.tscWatch.libFile, fileWithError, fileWithoutError, tsconfig],
|
||||
{ currentDirectory: `${projectsLocation}/${solution}` }
|
||||
sys: () => createWatchedSystem(
|
||||
[libFile, fileWithError, fileWithoutError, tsconfig],
|
||||
{ currentDirectory: `${"/user/username/projects"}/${solution}` }
|
||||
),
|
||||
changes: [
|
||||
fixError
|
||||
]
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "programUpdates",
|
||||
subScenario: "reportErrors/declarationEmitErrors/when file with no error changes",
|
||||
commandLineArgs: ["-b", "-w", subProject],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
[ts.tscWatch.libFile, fileWithError, fileWithoutError, tsconfig],
|
||||
{ currentDirectory: `${projectsLocation}/${solution}` }
|
||||
sys: () => createWatchedSystem(
|
||||
[libFile, fileWithError, fileWithoutError, tsconfig],
|
||||
{ currentDirectory: `${"/user/username/projects"}/${solution}` }
|
||||
),
|
||||
changes: [
|
||||
changeFileWithoutError
|
||||
@@ -432,19 +447,19 @@ let x: string = 10;`),
|
||||
});
|
||||
|
||||
describe("when reporting errors on introducing error", () => {
|
||||
const introduceError: ts.tscWatch.TscWatchCompileChange = {
|
||||
const introduceError: TscWatchCompileChange = {
|
||||
caption: "Introduce error",
|
||||
change: sys => sys.writeFile(fileWithError.path, fileWithError.content),
|
||||
timeouts: incrementalBuild,
|
||||
};
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "programUpdates",
|
||||
subScenario: "reportErrors/declarationEmitErrors/introduceError/when fixing errors only changed file is emitted",
|
||||
commandLineArgs: ["-b", "-w", subProject],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
[ts.tscWatch.libFile, fileWithFixedError, fileWithoutError, tsconfig],
|
||||
{ currentDirectory: `${projectsLocation}/${solution}` }
|
||||
sys: () => createWatchedSystem(
|
||||
[libFile, fileWithFixedError, fileWithoutError, tsconfig],
|
||||
{ currentDirectory: `${"/user/username/projects"}/${solution}` }
|
||||
),
|
||||
changes: [
|
||||
introduceError,
|
||||
@@ -452,13 +467,13 @@ let x: string = 10;`),
|
||||
]
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "programUpdates",
|
||||
subScenario: "reportErrors/declarationEmitErrors/introduceError/when file with no error changes",
|
||||
commandLineArgs: ["-b", "-w", subProject],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
[ts.tscWatch.libFile, fileWithFixedError, fileWithoutError, tsconfig],
|
||||
{ currentDirectory: `${projectsLocation}/${solution}` }
|
||||
sys: () => createWatchedSystem(
|
||||
[libFile, fileWithFixedError, fileWithoutError, tsconfig],
|
||||
{ currentDirectory: `${"/user/username/projects"}/${solution}` }
|
||||
),
|
||||
changes: [
|
||||
introduceError,
|
||||
@@ -469,11 +484,11 @@ let x: string = 10;`),
|
||||
});
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "programUpdates",
|
||||
subScenario: "incremental updates in verbose mode",
|
||||
commandLineArgs: ["-b", "-w", `sample1/${SubProject.tests}`, "-verbose"],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(allFiles, { currentDirectory: projectsLocation }),
|
||||
sys: () => createWatchedSystem(allFiles, { currentDirectory: "/user/username/projects" }),
|
||||
changes: [
|
||||
{
|
||||
caption: "Make non dts change",
|
||||
@@ -496,104 +511,104 @@ export function someFn() { }`),
|
||||
],
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "programUpdates",
|
||||
subScenario: "works when noUnusedParameters changes to false",
|
||||
commandLineArgs: ["-b", "-w"],
|
||||
sys: () => {
|
||||
const index: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/index.ts`,
|
||||
const index: File = {
|
||||
path: `/user/username/projects/myproject/index.ts`,
|
||||
content: `const fn = (a: string, b: string) => b;`
|
||||
};
|
||||
const configFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const configFile: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
noUnusedParameters: true
|
||||
}
|
||||
})
|
||||
};
|
||||
return ts.tscWatch.createWatchedSystem([index, configFile, ts.tscWatch.libFile], { currentDirectory: ts.tscWatch.projectRoot });
|
||||
return createWatchedSystem([index, configFile, libFile], { currentDirectory: "/user/username/projects/myproject" });
|
||||
},
|
||||
changes: [
|
||||
{
|
||||
caption: "Change tsconfig to set noUnusedParameters to false",
|
||||
change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/tsconfig.json`, JSON.stringify({
|
||||
change: sys => sys.writeFile(`/user/username/projects/myproject/tsconfig.json`, JSON.stringify({
|
||||
compilerOptions: {
|
||||
noUnusedParameters: false
|
||||
}
|
||||
})),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks,
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
},
|
||||
]
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "programUpdates",
|
||||
subScenario: "should not trigger recompilation because of program emit",
|
||||
commandLineArgs: ["-b", "-w", `sample1/${SubProject.core}`, "-verbose"],
|
||||
sys: () => ts.tscWatch.createWatchedSystem([ts.tscWatch.libFile, ...core], { currentDirectory: projectsLocation }),
|
||||
sys: () => createWatchedSystem([libFile, ...core], { currentDirectory: "/user/username/projects" }),
|
||||
changes: [
|
||||
ts.tscWatch.noopChange,
|
||||
noopChange,
|
||||
{
|
||||
caption: "Add new file",
|
||||
change: sys => sys.writeFile(`sample1/${SubProject.core}/file3.ts`, `export const y = 10;`),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1)
|
||||
},
|
||||
ts.tscWatch.noopChange,
|
||||
noopChange,
|
||||
]
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "programUpdates",
|
||||
subScenario: "should not trigger recompilation because of program emit with outDir specified",
|
||||
commandLineArgs: ["-b", "-w", `sample1/${SubProject.core}`, "-verbose"],
|
||||
sys: () => {
|
||||
const [coreConfig, ...rest] = core;
|
||||
const newCoreConfig: ts.tscWatch.File = { path: coreConfig.path, content: JSON.stringify({ compilerOptions: { composite: true, outDir: "outDir" } }) };
|
||||
return ts.tscWatch.createWatchedSystem([ts.tscWatch.libFile, newCoreConfig, ...rest], { currentDirectory: projectsLocation });
|
||||
const newCoreConfig: File = { path: coreConfig.path, content: JSON.stringify({ compilerOptions: { composite: true, outDir: "outDir" } }) };
|
||||
return createWatchedSystem([libFile, newCoreConfig, ...rest], { currentDirectory: "/user/username/projects" });
|
||||
},
|
||||
changes: [
|
||||
ts.tscWatch.noopChange,
|
||||
noopChange,
|
||||
{
|
||||
caption: "Add new file",
|
||||
change: sys => sys.writeFile(`sample1/${SubProject.core}/file3.ts`, `export const y = 10;`),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1)
|
||||
},
|
||||
ts.tscWatch.noopChange
|
||||
noopChange
|
||||
]
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "programUpdates",
|
||||
subScenario: "works with extended source files",
|
||||
commandLineArgs: ["-b", "-w", "-v", "project1.tsconfig.json", "project2.tsconfig.json"],
|
||||
sys: () => {
|
||||
const alphaExtendedConfigFile: ts.tscWatch.File = {
|
||||
const alphaExtendedConfigFile: File = {
|
||||
path: "/a/b/alpha.tsconfig.json",
|
||||
content: "{}"
|
||||
};
|
||||
const project1Config: ts.tscWatch.File = {
|
||||
const project1Config: File = {
|
||||
path: "/a/b/project1.tsconfig.json",
|
||||
content: JSON.stringify({
|
||||
extends: "./alpha.tsconfig.json",
|
||||
compilerOptions: {
|
||||
composite: true,
|
||||
},
|
||||
files: [ts.tscWatch.commonFile1.path, ts.tscWatch.commonFile2.path]
|
||||
files: [commonFile1.path, commonFile2.path]
|
||||
})
|
||||
};
|
||||
const bravoExtendedConfigFile: ts.tscWatch.File = {
|
||||
const bravoExtendedConfigFile: File = {
|
||||
path: "/a/b/bravo.tsconfig.json",
|
||||
content: JSON.stringify({
|
||||
extends: "./alpha.tsconfig.json"
|
||||
})
|
||||
};
|
||||
const otherFile: ts.tscWatch.File = {
|
||||
const otherFile: File = {
|
||||
path: "/a/b/other.ts",
|
||||
content: "let z = 0;",
|
||||
};
|
||||
const project2Config: ts.tscWatch.File = {
|
||||
const project2Config: File = {
|
||||
path: "/a/b/project2.tsconfig.json",
|
||||
content: JSON.stringify({
|
||||
extends: "./bravo.tsconfig.json",
|
||||
@@ -603,9 +618,9 @@ export function someFn() { }`),
|
||||
files: [otherFile.path]
|
||||
})
|
||||
};
|
||||
return ts.tscWatch.createWatchedSystem([
|
||||
ts.tscWatch.libFile,
|
||||
alphaExtendedConfigFile, project1Config, ts.tscWatch.commonFile1, ts.tscWatch.commonFile2,
|
||||
return createWatchedSystem([
|
||||
libFile,
|
||||
alphaExtendedConfigFile, project1Config, commonFile1, commonFile2,
|
||||
bravoExtendedConfigFile, project2Config, otherFile
|
||||
], { currentDirectory: "/a/b" });
|
||||
},
|
||||
@@ -615,12 +630,15 @@ export function someFn() { }`),
|
||||
change: sys => sys.writeFile("/a/b/alpha.tsconfig.json", JSON.stringify({
|
||||
compilerOptions: { strict: true }
|
||||
})),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun // Build project1
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1) // Build project1
|
||||
},
|
||||
{
|
||||
caption: "Build project 2",
|
||||
change: ts.noop,
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout // Build project2
|
||||
timeouts: sys => { // Build project2
|
||||
sys.checkTimeoutQueueLengthAndRun(1);
|
||||
sys.checkTimeoutQueueLength(0);
|
||||
},
|
||||
},
|
||||
{
|
||||
caption: "change bravo config",
|
||||
@@ -628,34 +646,43 @@ export function someFn() { }`),
|
||||
extends: "./alpha.tsconfig.json",
|
||||
compilerOptions: { strict: false }
|
||||
})),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout // Build project2
|
||||
timeouts: sys => { // Build project2
|
||||
sys.checkTimeoutQueueLengthAndRun(1);
|
||||
sys.checkTimeoutQueueLength(0);
|
||||
},
|
||||
},
|
||||
{
|
||||
caption: "project 2 extends alpha",
|
||||
change: sys => sys.writeFile("/a/b/project2.tsconfig.json", JSON.stringify({
|
||||
extends: "./alpha.tsconfig.json",
|
||||
})),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout // Build project2
|
||||
timeouts: sys => { // Build project2
|
||||
sys.checkTimeoutQueueLengthAndRun(1);
|
||||
sys.checkTimeoutQueueLength(0);
|
||||
},
|
||||
},
|
||||
{
|
||||
caption: "update aplha config",
|
||||
change: sys => sys.writeFile("/a/b/alpha.tsconfig.json", "{}"),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, // build project1
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), // build project1
|
||||
},
|
||||
{
|
||||
caption: "Build project 2",
|
||||
change: ts.noop,
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout // Build project2
|
||||
timeouts: sys => { // Build project2
|
||||
sys.checkTimeoutQueueLengthAndRun(1);
|
||||
sys.checkTimeoutQueueLength(0);
|
||||
},
|
||||
},
|
||||
]
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "programUpdates",
|
||||
subScenario: "works correctly when project with extended config is removed",
|
||||
commandLineArgs: ["-b", "-w", "-v"],
|
||||
sys: () => {
|
||||
const alphaExtendedConfigFile: ts.tscWatch.File = {
|
||||
const alphaExtendedConfigFile: File = {
|
||||
path: "/a/b/alpha.tsconfig.json",
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
@@ -663,17 +690,17 @@ export function someFn() { }`),
|
||||
}
|
||||
})
|
||||
};
|
||||
const project1Config: ts.tscWatch.File = {
|
||||
const project1Config: File = {
|
||||
path: "/a/b/project1.tsconfig.json",
|
||||
content: JSON.stringify({
|
||||
extends: "./alpha.tsconfig.json",
|
||||
compilerOptions: {
|
||||
composite: true,
|
||||
},
|
||||
files: [ts.tscWatch.commonFile1.path, ts.tscWatch.commonFile2.path]
|
||||
files: [commonFile1.path, commonFile2.path]
|
||||
})
|
||||
};
|
||||
const bravoExtendedConfigFile: ts.tscWatch.File = {
|
||||
const bravoExtendedConfigFile: File = {
|
||||
path: "/a/b/bravo.tsconfig.json",
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
@@ -681,11 +708,11 @@ export function someFn() { }`),
|
||||
}
|
||||
})
|
||||
};
|
||||
const otherFile: ts.tscWatch.File = {
|
||||
const otherFile: File = {
|
||||
path: "/a/b/other.ts",
|
||||
content: "let z = 0;",
|
||||
};
|
||||
const project2Config: ts.tscWatch.File = {
|
||||
const project2Config: File = {
|
||||
path: "/a/b/project2.tsconfig.json",
|
||||
content: JSON.stringify({
|
||||
extends: "./bravo.tsconfig.json",
|
||||
@@ -695,7 +722,7 @@ export function someFn() { }`),
|
||||
files: [otherFile.path]
|
||||
})
|
||||
};
|
||||
const configFile: ts.tscWatch.File = {
|
||||
const configFile: File = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: JSON.stringify({
|
||||
references: [
|
||||
@@ -709,9 +736,9 @@ export function someFn() { }`),
|
||||
files: [],
|
||||
})
|
||||
};
|
||||
return ts.tscWatch.createWatchedSystem([
|
||||
ts.tscWatch.libFile, configFile,
|
||||
alphaExtendedConfigFile, project1Config, ts.tscWatch.commonFile1, ts.tscWatch.commonFile2,
|
||||
return createWatchedSystem([
|
||||
libFile, configFile,
|
||||
alphaExtendedConfigFile, project1Config, commonFile1, commonFile2,
|
||||
bravoExtendedConfigFile, project2Config, otherFile
|
||||
], { currentDirectory: "/a/b" });
|
||||
},
|
||||
@@ -726,19 +753,22 @@ export function someFn() { }`),
|
||||
],
|
||||
files: [],
|
||||
})),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout,
|
||||
timeouts: sys => {
|
||||
sys.checkTimeoutQueueLengthAndRun(1);
|
||||
sys.checkTimeoutQueueLength(0);
|
||||
},
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "programUpdates",
|
||||
subScenario: "tsbuildinfo has error",
|
||||
sys: () => ts.tscWatch.createWatchedSystem({
|
||||
sys: () => createWatchedSystem({
|
||||
"/src/project/main.ts": "export const x = 10;",
|
||||
"/src/project/tsconfig.json": "{}",
|
||||
"/src/project/tsconfig.tsbuildinfo": "Some random string",
|
||||
[ts.tscWatch.libFile.path]: ts.tscWatch.libFile.content,
|
||||
[libFile.path]: libFile.content,
|
||||
}),
|
||||
commandLineArgs: ["--b", "src/project", "-i", "-w"],
|
||||
changes: ts.emptyArray
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { createWatchedSystem, File, libFile } from "../virtualFileSystemWithWatch";
|
||||
import { noopChange, TscWatchCompileChange, verifyTscWatch } from "../tscWatch/helpers";
|
||||
|
||||
describe("unittests:: tsbuildWatch:: watchMode:: projectsBuilding", () => {
|
||||
function pkgs<T>(cb: (index: number) => T, count: number, startIndex?: number): T[] {
|
||||
@@ -11,14 +13,14 @@ describe("unittests:: tsbuildWatch:: watchMode:: projectsBuilding", () => {
|
||||
function createPkgReference(index: number) {
|
||||
return { path: `./pkg${index}` };
|
||||
}
|
||||
function pkgFiles(index: number): ts.tscWatch.File[] {
|
||||
function pkgFiles(index: number): File[] {
|
||||
return [
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/pkg${index}/index.ts`,
|
||||
path: `/user/username/projects/myproject/pkg${index}/index.ts`,
|
||||
content: `export const pkg${index} = ${index};`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/pkg${index}/tsconfig.json`,
|
||||
path: `/user/username/projects/myproject/pkg${index}/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { composite: true },
|
||||
references: index === 0 ?
|
||||
@@ -28,158 +30,158 @@ describe("unittests:: tsbuildWatch:: watchMode:: projectsBuilding", () => {
|
||||
}
|
||||
];
|
||||
}
|
||||
function solution(maxPkgs: number): ts.tscWatch.File {
|
||||
function solution(maxPkgs: number): File {
|
||||
return {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
references: pkgs(createPkgReference, maxPkgs),
|
||||
files: [],
|
||||
})
|
||||
};
|
||||
}
|
||||
function checkBuildPkg(startIndex: number, count: number): ts.tscWatch.TscWatchCompileChange {
|
||||
function checkBuildPkg(startIndex: number, count: number): TscWatchCompileChange {
|
||||
return {
|
||||
caption: `build ${pkgs(index => `pkg${index}`, count, startIndex).join(",")}`,
|
||||
change: ts.noop,
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
};
|
||||
}
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "projectsBuilding",
|
||||
subScenario: `when there are 3 projects in a solution`,
|
||||
commandLineArgs: ["-b", "-w", "-v"],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
[ts.tscWatch.libFile, ...ts.flatMap(pkgs(pkgFiles, 3), ts.identity), solution(3)],
|
||||
{ currentDirectory: ts.tscWatch.projectRoot }
|
||||
sys: () => createWatchedSystem(
|
||||
[libFile, ...ts.flatMap(pkgs(pkgFiles, 3), ts.identity), solution(3)],
|
||||
{ currentDirectory: "/user/username/projects/myproject" }
|
||||
),
|
||||
changes: [
|
||||
{
|
||||
caption: "dts doesn't change",
|
||||
change: sys => sys.appendFile(`${ts.tscWatch.projectRoot}/pkg0/index.ts`, `const someConst2 = 10;`),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, // Build pkg0 and update timestamps
|
||||
change: sys => sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `const someConst2 = 10;`),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), // Build pkg0 and update timestamps
|
||||
},
|
||||
ts.tscWatch.noopChange,
|
||||
noopChange,
|
||||
{
|
||||
caption: "dts change",
|
||||
change: sys => sys.appendFile(`${ts.tscWatch.projectRoot}/pkg0/index.ts`, `export const someConst = 10;`),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun // Build pkg0
|
||||
change: sys => sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `export const someConst = 10;`),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1) // Build pkg0
|
||||
},
|
||||
checkBuildPkg(1, 2),
|
||||
ts.tscWatch.noopChange,
|
||||
noopChange,
|
||||
]
|
||||
});
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "projectsBuilding",
|
||||
subScenario: `when there are 5 projects in a solution`,
|
||||
commandLineArgs: ["-b", "-w", "-v"],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
[ts.tscWatch.libFile, ...ts.flatMap(pkgs(pkgFiles, 5), ts.identity), solution(5)],
|
||||
{ currentDirectory: ts.tscWatch.projectRoot }
|
||||
sys: () => createWatchedSystem(
|
||||
[libFile, ...ts.flatMap(pkgs(pkgFiles, 5), ts.identity), solution(5)],
|
||||
{ currentDirectory: "/user/username/projects/myproject" }
|
||||
),
|
||||
changes: [
|
||||
{
|
||||
caption: "dts doesn't change",
|
||||
change: sys => sys.appendFile(`${ts.tscWatch.projectRoot}/pkg0/index.ts`, `const someConst2 = 10;`),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, // Build pkg0 and update timestamps
|
||||
change: sys => sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `const someConst2 = 10;`),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), // Build pkg0 and update timestamps
|
||||
},
|
||||
ts.tscWatch.noopChange,
|
||||
noopChange,
|
||||
{
|
||||
caption: "dts change",
|
||||
change: sys => sys.appendFile(`${ts.tscWatch.projectRoot}/pkg0/index.ts`, `export const someConst = 10;`),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun // Build pkg0
|
||||
change: sys => sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `export const someConst = 10;`),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1) // Build pkg0
|
||||
},
|
||||
checkBuildPkg(1, 4),
|
||||
ts.tscWatch.noopChange,
|
||||
noopChange,
|
||||
]
|
||||
});
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "projectsBuilding",
|
||||
subScenario: `when there are 8 projects in a solution`,
|
||||
commandLineArgs: ["-b", "-w", "-v"],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
[ts.tscWatch.libFile, ...ts.flatMap(pkgs(pkgFiles, 8), ts.identity), solution(8)],
|
||||
{ currentDirectory: ts.tscWatch.projectRoot }
|
||||
sys: () => createWatchedSystem(
|
||||
[libFile, ...ts.flatMap(pkgs(pkgFiles, 8), ts.identity), solution(8)],
|
||||
{ currentDirectory: "/user/username/projects/myproject" }
|
||||
),
|
||||
changes: [
|
||||
{
|
||||
caption: "dts doesn't change",
|
||||
change: sys => sys.appendFile(`${ts.tscWatch.projectRoot}/pkg0/index.ts`, `const someConst2 = 10;`),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, // Build pkg0 and update timestamps
|
||||
change: sys => sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `const someConst2 = 10;`),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), // Build pkg0 and update timestamps
|
||||
},
|
||||
ts.tscWatch.noopChange,
|
||||
noopChange,
|
||||
{
|
||||
caption: "dts change",
|
||||
change: sys => sys.appendFile(`${ts.tscWatch.projectRoot}/pkg0/index.ts`, `export const someConst = 10;`),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun // Build pkg0
|
||||
change: sys => sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `export const someConst = 10;`),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1) // Build pkg0
|
||||
},
|
||||
checkBuildPkg(1, 5),
|
||||
checkBuildPkg(6, 2),
|
||||
ts.tscWatch.noopChange,
|
||||
noopChange,
|
||||
{
|
||||
caption: "dts change2",
|
||||
change: sys => sys.appendFile(`${ts.tscWatch.projectRoot}/pkg0/index.ts`, `export const someConst3 = 10;`),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun // Build pkg0
|
||||
change: sys => sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `export const someConst3 = 10;`),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1) // Build pkg0
|
||||
},
|
||||
checkBuildPkg(1, 5),
|
||||
{
|
||||
caption: "change while building",
|
||||
change: sys => sys.appendFile(`${ts.tscWatch.projectRoot}/pkg0/index.ts`, `const someConst4 = 10;`),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun // Build pkg0
|
||||
change: sys => sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `const someConst4 = 10;`),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1) // Build pkg0
|
||||
},
|
||||
checkBuildPkg(6, 2),
|
||||
ts.tscWatch.noopChange,
|
||||
noopChange,
|
||||
]
|
||||
});
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "projectsBuilding",
|
||||
subScenario: `when there are 23 projects in a solution`,
|
||||
commandLineArgs: ["-b", "-w", "-v"],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
[ts.tscWatch.libFile, ...ts.flatMap(pkgs(pkgFiles, 23), ts.identity), solution(23)],
|
||||
{ currentDirectory: ts.tscWatch.projectRoot }
|
||||
sys: () => createWatchedSystem(
|
||||
[libFile, ...ts.flatMap(pkgs(pkgFiles, 23), ts.identity), solution(23)],
|
||||
{ currentDirectory: "/user/username/projects/myproject" }
|
||||
),
|
||||
changes: [
|
||||
{
|
||||
caption: "dts doesn't change",
|
||||
change: sys => sys.appendFile(`${ts.tscWatch.projectRoot}/pkg0/index.ts`, `const someConst2 = 10;`),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, // Build pkg0 and update timestamps
|
||||
change: sys => sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `const someConst2 = 10;`),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), // Build pkg0 and update timestamps
|
||||
},
|
||||
ts.tscWatch.noopChange,
|
||||
noopChange,
|
||||
{
|
||||
caption: "dts change",
|
||||
change: sys => sys.appendFile(`${ts.tscWatch.projectRoot}/pkg0/index.ts`, `export const someConst = 10;`),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun // Build pkg0
|
||||
change: sys => sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `export const someConst = 10;`),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1) // Build pkg0
|
||||
},
|
||||
checkBuildPkg(1, 5),
|
||||
checkBuildPkg(6, 5),
|
||||
checkBuildPkg(11, 5),
|
||||
checkBuildPkg(16, 5),
|
||||
checkBuildPkg(21, 3),
|
||||
ts.tscWatch.noopChange,
|
||||
noopChange,
|
||||
{
|
||||
caption: "dts change2",
|
||||
change: sys => sys.appendFile(`${ts.tscWatch.projectRoot}/pkg0/index.ts`, `export const someConst3 = 10;`),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun // Build pkg0
|
||||
change: sys => sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `export const someConst3 = 10;`),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1) // Build pkg0
|
||||
},
|
||||
checkBuildPkg(1, 5),
|
||||
checkBuildPkg(6, 5),
|
||||
{
|
||||
caption: "change while building",
|
||||
change: sys => sys.appendFile(`${ts.tscWatch.projectRoot}/pkg0/index.ts`, `const someConst4 = 10;`),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun // Build pkg0
|
||||
change: sys => sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `const someConst4 = 10;`),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1) // Build pkg0
|
||||
},
|
||||
checkBuildPkg(11, 5),
|
||||
{
|
||||
caption: "change while building: dts changes",
|
||||
change: sys => sys.appendFile(`${ts.tscWatch.projectRoot}/pkg0/index.ts`, `export const someConst5 = 10;`),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun // Build pkg0
|
||||
change: sys => sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `export const someConst5 = 10;`),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1) // Build pkg0
|
||||
},
|
||||
checkBuildPkg(1, 5),
|
||||
checkBuildPkg(6, 5),
|
||||
checkBuildPkg(11, 5),
|
||||
checkBuildPkg(16, 5),
|
||||
checkBuildPkg(21, 3),
|
||||
ts.tscWatch.noopChange,
|
||||
noopChange,
|
||||
]
|
||||
});
|
||||
});
|
||||
@@ -1,8 +1,10 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { createWatchedSystem, File, libFile } from "../virtualFileSystemWithWatch";
|
||||
import { createBaseline, createSolutionBuilderWithWatchHostForBaseline, runWatchBaseline } from "../tscWatch/helpers";
|
||||
|
||||
it("unittests:: tsbuildWatch:: watchMode:: Public API with custom transformers", () => {
|
||||
const solution: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const solution: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
references: [
|
||||
{ path: "./shared/tsconfig.json" },
|
||||
@@ -11,29 +13,29 @@ it("unittests:: tsbuildWatch:: watchMode:: Public API with custom transformers",
|
||||
files: []
|
||||
})
|
||||
};
|
||||
const sharedConfig: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/shared/tsconfig.json`,
|
||||
const sharedConfig: File = {
|
||||
path: `/user/username/projects/myproject/shared/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { composite: true },
|
||||
})
|
||||
};
|
||||
const sharedIndex: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/shared/index.ts`,
|
||||
const sharedIndex: File = {
|
||||
path: `/user/username/projects/myproject/shared/index.ts`,
|
||||
content: `export function f1() { }
|
||||
export class c { }
|
||||
export enum e { }
|
||||
// leading
|
||||
export function f2() { } // trailing`
|
||||
};
|
||||
const webpackConfig: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/webpack/tsconfig.json`,
|
||||
const webpackConfig: File = {
|
||||
path: `/user/username/projects/myproject/webpack/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { composite: true, },
|
||||
references: [{ path: "../shared/tsconfig.json" }]
|
||||
})
|
||||
};
|
||||
const webpackIndex: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/webpack/index.ts`,
|
||||
const webpackIndex: File = {
|
||||
path: `/user/username/projects/myproject/webpack/index.ts`,
|
||||
content: `export function f2() { }
|
||||
export class c2 { }
|
||||
export enum e2 { }
|
||||
@@ -41,12 +43,12 @@ export enum e2 { }
|
||||
export function f22() { } // trailing`
|
||||
};
|
||||
const commandLineArgs = ["--b", "--w"];
|
||||
const { sys, baseline, oldSnap, cb, getPrograms } = ts.tscWatch.createBaseline(ts.tscWatch.createWatchedSystem([ts.tscWatch.libFile, solution, sharedConfig, sharedIndex, webpackConfig, webpackIndex], { currentDirectory: ts.tscWatch.projectRoot }));
|
||||
const buildHost = ts.tscWatch.createSolutionBuilderWithWatchHostForBaseline(sys, cb);
|
||||
const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem([libFile, solution, sharedConfig, sharedIndex, webpackConfig, webpackIndex], { currentDirectory: "/user/username/projects/myproject" }));
|
||||
const buildHost = createSolutionBuilderWithWatchHostForBaseline(sys, cb);
|
||||
buildHost.getCustomTransformers = getCustomTransformers;
|
||||
const builder = ts.createSolutionBuilderWithWatch(buildHost, [solution.path], { verbose: true });
|
||||
builder.build();
|
||||
ts.tscWatch.runWatchBaseline({
|
||||
runWatchBaseline({
|
||||
scenario: "publicApi",
|
||||
subScenario: "with custom transformers",
|
||||
commandLineArgs,
|
||||
|
||||
@@ -1,26 +1,28 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { createWatchedSystem, getTsBuildProjectFile, libFile } from "../virtualFileSystemWithWatch";
|
||||
import { libContent } from "../tsc/helpers";
|
||||
import { verifyTscWatch } from "../tscWatch/helpers";
|
||||
|
||||
describe("unittests:: tsbuildWatch:: watchMode:: with reexport when referenced project reexports definitions from another file", () => {
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "reexport",
|
||||
subScenario: "Reports errors correctly",
|
||||
commandLineArgs: ["-b", "-w", "-verbose", "src"],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
sys: () => createWatchedSystem(
|
||||
[
|
||||
...[
|
||||
"src/tsconfig.json",
|
||||
"src/main/tsconfig.json", "src/main/index.ts",
|
||||
"src/pure/tsconfig.json", "src/pure/index.ts", "src/pure/session.ts"
|
||||
]
|
||||
.map(f => ts.TestFSWithWatch.getTsBuildProjectFile("reexport", f)),
|
||||
{ path: ts.tscWatch.libFile.path, content: ts.libContent }
|
||||
.map(f => getTsBuildProjectFile("reexport", f)),
|
||||
{ path: libFile.path, content: libContent }
|
||||
],
|
||||
{ currentDirectory: `${ts.TestFSWithWatch.tsbuildProjectsLocation}/reexport` }
|
||||
{ currentDirectory: `/user/username/projects/reexport` }
|
||||
),
|
||||
changes: [
|
||||
{
|
||||
caption: "Introduce error",
|
||||
change: sys => ts.tscWatch.replaceFileText(sys, `${ts.TestFSWithWatch.tsbuildProjectsLocation}/reexport/src/pure/session.ts`, "// ", ""),
|
||||
change: sys => sys.replaceFileText(`/user/username/projects/reexport/src/pure/session.ts`, "// ", ""),
|
||||
timeouts: sys => {
|
||||
sys.checkTimeoutQueueLengthAndRun(1); // build src/pure
|
||||
sys.checkTimeoutQueueLengthAndRun(1); // build src/main and src
|
||||
@@ -29,7 +31,7 @@ describe("unittests:: tsbuildWatch:: watchMode:: with reexport when referenced p
|
||||
},
|
||||
{
|
||||
caption: "Fix error",
|
||||
change: sys => ts.tscWatch.replaceFileText(sys, `${ts.TestFSWithWatch.tsbuildProjectsLocation}/reexport/src/pure/session.ts`, "bar: ", "// bar: "),
|
||||
change: sys => sys.replaceFileText(`/user/username/projects/reexport/src/pure/session.ts`, "bar: ", "// bar: "),
|
||||
timeouts: sys => {
|
||||
sys.checkTimeoutQueueLengthAndRun(1); // build src/pure
|
||||
sys.checkTimeoutQueueLengthAndRun(1); // build src/main and src
|
||||
|
||||
@@ -1,23 +1,25 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { createWatchedSystem, File, libFile, TestServerHost } from "../virtualFileSystemWithWatch";
|
||||
import { createBaseline, createSolutionBuilderWithWatchHostForBaseline, runWatchBaseline } from "../tscWatch/helpers";
|
||||
|
||||
describe("unittests:: tsbuildWatch:: watchEnvironment:: tsbuild:: watchMode:: with different watch environments", () => {
|
||||
it("watchFile on same file multiple times because file is part of multiple projects", () => {
|
||||
const project = `${ts.TestFSWithWatch.tsbuildProjectsLocation}/myproject`;
|
||||
const project = `/user/username/projects/myproject`;
|
||||
let maxPkgs = 4;
|
||||
const configPath = `${project}/tsconfig.json`;
|
||||
const typing: ts.tscWatch.File = {
|
||||
const typing: File = {
|
||||
path: `${project}/typings/xterm.d.ts`,
|
||||
content: "export const typing = 10;"
|
||||
};
|
||||
|
||||
const allPkgFiles = pkgs(pkgFiles);
|
||||
const system = ts.tscWatch.createWatchedSystem([ts.tscWatch.libFile, typing, ...flatArray(allPkgFiles)], { currentDirectory: project });
|
||||
const system = createWatchedSystem([libFile, typing, ...flatArray(allPkgFiles)], { currentDirectory: project });
|
||||
writePkgReferences(system);
|
||||
const { sys, baseline, oldSnap, cb, getPrograms } = ts.tscWatch.createBaseline(system);
|
||||
const host = ts.tscWatch.createSolutionBuilderWithWatchHostForBaseline(sys, cb);
|
||||
const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(system);
|
||||
const host = createSolutionBuilderWithWatchHostForBaseline(sys, cb);
|
||||
const solutionBuilder = ts.createSolutionBuilderWithWatch(host, ["tsconfig.json"], { watch: true, verbose: true });
|
||||
solutionBuilder.build();
|
||||
ts.tscWatch.runWatchBaseline({
|
||||
runWatchBaseline({
|
||||
scenario: "watchEnvironment",
|
||||
subScenario: `same file in multiple projects with single watcher per file`,
|
||||
commandLineArgs: ["--b", "--w"],
|
||||
@@ -31,7 +33,8 @@ describe("unittests:: tsbuildWatch:: watchEnvironment:: tsbuild:: watchMode:: wi
|
||||
change: sys => sys.writeFile(typing.path, `${typing.content}export const typing1 = 10;`),
|
||||
timeouts: sys => {
|
||||
sys.checkTimeoutQueueLengthAndRun(1);
|
||||
ts.tscWatch.checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout(sys);
|
||||
sys.checkTimeoutQueueLengthAndRun(1);
|
||||
sys.checkTimeoutQueueLength(0);
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -41,14 +44,15 @@ describe("unittests:: tsbuildWatch:: watchEnvironment:: tsbuild:: watchMode:: wi
|
||||
maxPkgs--;
|
||||
writePkgReferences(sys);
|
||||
},
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
},
|
||||
{
|
||||
caption: "modify typing file",
|
||||
change: sys => sys.writeFile(typing.path, typing.content),
|
||||
timeouts: sys => {
|
||||
sys.checkTimeoutQueueLengthAndRun(1);
|
||||
ts.tscWatch.checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout(sys);
|
||||
sys.checkTimeoutQueueLengthAndRun(1);
|
||||
sys.checkTimeoutQueueLength(0);
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -58,7 +62,7 @@ describe("unittests:: tsbuildWatch:: watchEnvironment:: tsbuild:: watchMode:: wi
|
||||
maxPkgs = 0;
|
||||
writePkgReferences(sys);
|
||||
},
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
},
|
||||
{
|
||||
caption: "modify typing file",
|
||||
@@ -82,7 +86,7 @@ describe("unittests:: tsbuildWatch:: watchEnvironment:: tsbuild:: watchMode:: wi
|
||||
function createPkgReference(index: number) {
|
||||
return { path: `./pkg${index}` };
|
||||
}
|
||||
function pkgFiles(index: number): ts.tscWatch.File[] {
|
||||
function pkgFiles(index: number): File[] {
|
||||
return [
|
||||
{
|
||||
path: `${project}/pkg${index}/index.ts`,
|
||||
@@ -100,7 +104,7 @@ describe("unittests:: tsbuildWatch:: watchEnvironment:: tsbuild:: watchMode:: wi
|
||||
}
|
||||
];
|
||||
}
|
||||
function writePkgReferences(system: ts.TestFSWithWatch.TestServerHost) {
|
||||
function writePkgReferences(system: TestServerHost) {
|
||||
system.writeFile(configPath, JSON.stringify({
|
||||
files: [],
|
||||
include: [],
|
||||
|
||||
@@ -1,46 +1,49 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as Utils from "../../_namespaces/Utils";
|
||||
import * as Harness from "../../_namespaces/Harness";
|
||||
import { createWatchedSystem, File, libFile } from "../virtualFileSystemWithWatch";
|
||||
import { baselineBuildInfo, CommandLineProgram } from "../tsc/helpers";
|
||||
import { applyChange, createBaseline, watchBaseline } from "../tscWatch/helpers";
|
||||
|
||||
describe("unittests:: tsc:: builder cancellationToken", () => {
|
||||
verifyCancellation(/*useBuildInfo*/ true, "when emitting buildInfo");
|
||||
verifyCancellation(/*useBuildInfo*/ false, "when using state");
|
||||
function verifyCancellation(useBuildInfo: boolean, scenario: string) {
|
||||
it(scenario, () => {
|
||||
const aFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/a.ts`,
|
||||
const aFile: File = {
|
||||
path: `/user/username/projects/myproject/a.ts`,
|
||||
content: Utils.dedent`
|
||||
import {B} from './b';
|
||||
declare var console: any;
|
||||
let b = new B();
|
||||
console.log(b.c.d);`
|
||||
};
|
||||
const bFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/b.ts`,
|
||||
const bFile: File = {
|
||||
path: `/user/username/projects/myproject/b.ts`,
|
||||
content: Utils.dedent`
|
||||
import {C} from './c';
|
||||
export class B {
|
||||
c = new C();
|
||||
}`
|
||||
};
|
||||
const cFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/c.ts`,
|
||||
const cFile: File = {
|
||||
path: `/user/username/projects/myproject/c.ts`,
|
||||
content: Utils.dedent`
|
||||
export class C {
|
||||
d = 1;
|
||||
}`
|
||||
};
|
||||
const dFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/d.ts`,
|
||||
const dFile: File = {
|
||||
path: `/user/username/projects/myproject/d.ts`,
|
||||
content: "export class D { }"
|
||||
};
|
||||
const config: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const config: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: JSON.stringify({ compilerOptions: { incremental: true, declaration: true } })
|
||||
};
|
||||
const { sys, baseline, oldSnap: originalSnap } = ts.tscWatch.createBaseline(ts.tscWatch.createWatchedSystem(
|
||||
[aFile, bFile, cFile, dFile, config, ts.tscWatch.libFile],
|
||||
{ currentDirectory: ts.tscWatch.projectRoot }
|
||||
const { sys, baseline, oldSnap: originalSnap } = createBaseline(createWatchedSystem(
|
||||
[aFile, bFile, cFile, dFile, config, libFile],
|
||||
{ currentDirectory: "/user/username/projects/myproject" }
|
||||
));
|
||||
sys.exit = exitCode => sys.exitCode = exitCode;
|
||||
const reportDiagnostic = ts.createDiagnosticReporter(sys, /*pretty*/ true);
|
||||
@@ -53,8 +56,8 @@ describe("unittests:: tsc:: builder cancellationToken", () => {
|
||||
reportDiagnostic
|
||||
)!;
|
||||
const host = ts.createIncrementalCompilerHost(parsedConfig.options, sys);
|
||||
let programs: ts.CommandLineProgram[] = ts.emptyArray;
|
||||
let oldPrograms: ts.CommandLineProgram[] = ts.emptyArray;
|
||||
let programs: CommandLineProgram[] = ts.emptyArray;
|
||||
let oldPrograms: CommandLineProgram[] = ts.emptyArray;
|
||||
let builderProgram: ts.EmitAndSemanticDiagnosticsBuilderProgram = undefined!;
|
||||
let oldSnap = originalSnap;
|
||||
let cancel = false;
|
||||
@@ -73,7 +76,7 @@ describe("unittests:: tsc:: builder cancellationToken", () => {
|
||||
|
||||
// Cancel on first semantic operation
|
||||
// Change
|
||||
oldSnap = ts.tscWatch.applyChange(
|
||||
oldSnap = applyChange(
|
||||
sys,
|
||||
baseline,
|
||||
sys => sys.appendFile(cFile.path, "export function foo() {}"),
|
||||
@@ -91,8 +94,8 @@ describe("unittests:: tsc:: builder cancellationToken", () => {
|
||||
}
|
||||
cancel = false;
|
||||
builderProgram.emitBuildInfo();
|
||||
ts.baselineBuildInfo(builderProgram.getCompilerOptions(), sys);
|
||||
ts.tscWatch.watchBaseline({
|
||||
baselineBuildInfo(builderProgram.getCompilerOptions(), sys);
|
||||
watchBaseline({
|
||||
baseline,
|
||||
getPrograms: () => programs,
|
||||
oldPrograms,
|
||||
@@ -111,7 +114,7 @@ describe("unittests:: tsc:: builder cancellationToken", () => {
|
||||
Harness.Baseline.runBaseline(`tsc/cancellationToken/${scenario.split(" ").join("-")}.js`, baseline.join("\r\n"));
|
||||
|
||||
function noChange(caption: string) {
|
||||
oldSnap = ts.tscWatch.applyChange(sys, baseline, ts.noop, caption);
|
||||
oldSnap = applyChange(sys, baseline, ts.noop, caption);
|
||||
}
|
||||
|
||||
function updatePrograms() {
|
||||
@@ -139,8 +142,8 @@ describe("unittests:: tsc:: builder cancellationToken", () => {
|
||||
|
||||
function emitAndBaseline() {
|
||||
ts.emitFilesAndReportErrorsAndGetExitStatus(builderProgram, reportDiagnostic);
|
||||
ts.baselineBuildInfo(builderProgram.getCompilerOptions(), sys);
|
||||
ts.tscWatch.watchBaseline({
|
||||
baselineBuildInfo(builderProgram.getCompilerOptions(), sys);
|
||||
watchBaseline({
|
||||
baseline,
|
||||
getPrograms: () => programs,
|
||||
oldPrograms,
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as Utils from "../../_namespaces/Utils";
|
||||
import { loadProjectFromFiles, replaceText, verifyTsc, verifyTscWithEdits } from "./helpers";
|
||||
|
||||
describe("unittests:: tsc:: composite::", () => {
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "composite",
|
||||
subScenario: "when setting composite false on command line",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/project/src/main.ts": "export const x = 10;",
|
||||
"/src/project/tsconfig.json": Utils.dedent`
|
||||
{
|
||||
@@ -22,10 +22,10 @@ describe("unittests:: tsc:: composite::", () => {
|
||||
commandLineArgs: ["--composite", "false", "--p", "src/project"],
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "composite",
|
||||
subScenario: "when setting composite null on command line",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/project/src/main.ts": "export const x = 10;",
|
||||
"/src/project/tsconfig.json": Utils.dedent`
|
||||
{
|
||||
@@ -42,10 +42,10 @@ describe("unittests:: tsc:: composite::", () => {
|
||||
commandLineArgs: ["--composite", "null", "--p", "src/project"],
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "composite",
|
||||
subScenario: "when setting composite false on command line but has tsbuild info in config",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/project/src/main.ts": "export const x = 10;",
|
||||
"/src/project/tsconfig.json": Utils.dedent`
|
||||
{
|
||||
@@ -63,10 +63,10 @@ describe("unittests:: tsc:: composite::", () => {
|
||||
commandLineArgs: ["--composite", "false", "--p", "src/project"],
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "composite",
|
||||
subScenario: "when setting composite false and tsbuildinfo as null on command line but has tsbuild info in config",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/project/src/main.ts": "export const x = 10;",
|
||||
"/src/project/tsconfig.json": Utils.dedent`
|
||||
{
|
||||
@@ -84,10 +84,10 @@ describe("unittests:: tsc:: composite::", () => {
|
||||
commandLineArgs: ["--composite", "false", "--p", "src/project", "--tsBuildInfoFile", "null"],
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "composite",
|
||||
subScenario: "converting to modules",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/project/src/main.ts": "const x = 10;",
|
||||
"/src/project/tsconfig.json": JSON.stringify({
|
||||
compilerOptions: {
|
||||
@@ -100,7 +100,7 @@ describe("unittests:: tsc:: composite::", () => {
|
||||
edits: [
|
||||
{
|
||||
subScenario: "convert to modules",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/project/tsconfig.json", "none", "es2015"),
|
||||
modifyFs: fs => replaceText(fs, "/src/project/tsconfig.json", "none", "es2015"),
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
@@ -1,26 +1,28 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as Utils from "../../_namespaces/Utils";
|
||||
import { createWatchedSystem, FileOrFolderOrSymLink, isSymLink, libFile } from "../virtualFileSystemWithWatch";
|
||||
import { verifyTscWatch } from "../tscWatch/helpers";
|
||||
|
||||
describe("unittests:: tsc:: declarationEmit::", () => {
|
||||
interface VerifyDeclarationEmitInput {
|
||||
subScenario: string;
|
||||
files: ts.TestFSWithWatch.FileOrFolderOrSymLink[];
|
||||
files: FileOrFolderOrSymLink[];
|
||||
rootProject: string;
|
||||
changeCaseFileTestPath: (path: string) => boolean;
|
||||
}
|
||||
|
||||
function changeCaseFile(file: ts.TestFSWithWatch.FileOrFolderOrSymLink, testPath: (path: string) => boolean, replacePath: (path: string) => string): ts.TestFSWithWatch.FileOrFolderOrSymLink {
|
||||
return !ts.TestFSWithWatch.isSymLink(file) || !testPath(file.symLink) ?
|
||||
function changeCaseFile(file: FileOrFolderOrSymLink, testPath: (path: string) => boolean, replacePath: (path: string) => string): FileOrFolderOrSymLink {
|
||||
return !isSymLink(file) || !testPath(file.symLink) ?
|
||||
testPath(file.path) ? { ...file, path: replacePath(file.path) } : file :
|
||||
{ path: testPath(file.path) ? replacePath(file.path) : file.path, symLink: replacePath(file.symLink) };
|
||||
}
|
||||
|
||||
function verifyDeclarationEmit({ subScenario, files, rootProject, changeCaseFileTestPath }: VerifyDeclarationEmitInput) {
|
||||
describe(subScenario, () => {
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "declarationEmit",
|
||||
subScenario,
|
||||
sys: () => ts.tscWatch.createWatchedSystem(files, { currentDirectory: ts.tscWatch.projectRoot }),
|
||||
sys: () => createWatchedSystem(files, { currentDirectory: "/user/username/projects/myproject" }),
|
||||
commandLineArgs: ["-p", rootProject, "--explainFiles"],
|
||||
changes: ts.emptyArray
|
||||
});
|
||||
@@ -28,12 +30,12 @@ describe("unittests:: tsc:: declarationEmit::", () => {
|
||||
|
||||
const caseChangeScenario = `${subScenario} moduleCaseChange`;
|
||||
describe(caseChangeScenario, () => {
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "declarationEmit",
|
||||
subScenario: caseChangeScenario,
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
sys: () => createWatchedSystem(
|
||||
files.map(f => changeCaseFile(f, changeCaseFileTestPath, str => str.replace("myproject", "myProject"))),
|
||||
{ currentDirectory: ts.tscWatch.projectRoot }
|
||||
{ currentDirectory: "/user/username/projects/myproject" }
|
||||
),
|
||||
commandLineArgs: ["-p", rootProject, "--explainFiles"],
|
||||
changes: ts.emptyArray
|
||||
@@ -112,16 +114,16 @@ describe("unittests:: tsc:: declarationEmit::", () => {
|
||||
subScenario: "when same version is referenced through source and another symlinked package",
|
||||
rootProject: "plugin-one",
|
||||
files: [
|
||||
{ path: `${ts.tscWatch.projectRoot}/plugin-two/index.d.ts`, content: pluginTwoDts() },
|
||||
{ path: `${ts.tscWatch.projectRoot}/plugin-two/node_modules/typescript-fsa/package.json`, content: fsaPackageJson() },
|
||||
{ path: `${ts.tscWatch.projectRoot}/plugin-two/node_modules/typescript-fsa/index.d.ts`, content: fsaIndex() },
|
||||
{ path: `${ts.tscWatch.projectRoot}/plugin-one/tsconfig.json`, content: pluginOneConfig() },
|
||||
{ path: `${ts.tscWatch.projectRoot}/plugin-one/index.ts`, content: pluginOneIndex() },
|
||||
{ path: `${ts.tscWatch.projectRoot}/plugin-one/action.ts`, content: pluginOneAction() },
|
||||
{ path: `${ts.tscWatch.projectRoot}/plugin-one/node_modules/typescript-fsa/package.json`, content: fsaPackageJson() },
|
||||
{ path: `${ts.tscWatch.projectRoot}/plugin-one/node_modules/typescript-fsa/index.d.ts`, content: fsaIndex() },
|
||||
{ path: `${ts.tscWatch.projectRoot}/plugin-one/node_modules/plugin-two`, symLink: `${ts.tscWatch.projectRoot}/plugin-two` },
|
||||
ts.tscWatch.libFile
|
||||
{ path: `/user/username/projects/myproject/plugin-two/index.d.ts`, content: pluginTwoDts() },
|
||||
{ path: `/user/username/projects/myproject/plugin-two/node_modules/typescript-fsa/package.json`, content: fsaPackageJson() },
|
||||
{ path: `/user/username/projects/myproject/plugin-two/node_modules/typescript-fsa/index.d.ts`, content: fsaIndex() },
|
||||
{ path: `/user/username/projects/myproject/plugin-one/tsconfig.json`, content: pluginOneConfig() },
|
||||
{ path: `/user/username/projects/myproject/plugin-one/index.ts`, content: pluginOneIndex() },
|
||||
{ path: `/user/username/projects/myproject/plugin-one/action.ts`, content: pluginOneAction() },
|
||||
{ path: `/user/username/projects/myproject/plugin-one/node_modules/typescript-fsa/package.json`, content: fsaPackageJson() },
|
||||
{ path: `/user/username/projects/myproject/plugin-one/node_modules/typescript-fsa/index.d.ts`, content: fsaIndex() },
|
||||
{ path: `/user/username/projects/myproject/plugin-one/node_modules/plugin-two`, symLink: `/user/username/projects/myproject/plugin-two` },
|
||||
libFile
|
||||
],
|
||||
changeCaseFileTestPath: str => ts.stringContains(str, "/plugin-two"),
|
||||
});
|
||||
@@ -131,27 +133,27 @@ describe("unittests:: tsc:: declarationEmit::", () => {
|
||||
rootProject: "plugin-one",
|
||||
files: [
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/plugin-two/package.json`,
|
||||
path: `/user/username/projects/myproject/plugin-two/package.json`,
|
||||
content: JSON.stringify({
|
||||
name: "plugin-two",
|
||||
version: "0.1.3",
|
||||
main: "dist/commonjs/index.js"
|
||||
})
|
||||
},
|
||||
{ path: `${ts.tscWatch.projectRoot}/plugin-two/dist/commonjs/index.d.ts`, content: pluginTwoDts() },
|
||||
{ path: `${ts.tscWatch.projectRoot}/plugin-two/node_modules/typescript-fsa/package.json`, content: fsaPackageJson() },
|
||||
{ path: `${ts.tscWatch.projectRoot}/plugin-two/node_modules/typescript-fsa/index.d.ts`, content: fsaIndex() },
|
||||
{ path: `${ts.tscWatch.projectRoot}/plugin-one/tsconfig.json`, content: pluginOneConfig() },
|
||||
{ path: `/user/username/projects/myproject/plugin-two/dist/commonjs/index.d.ts`, content: pluginTwoDts() },
|
||||
{ path: `/user/username/projects/myproject/plugin-two/node_modules/typescript-fsa/package.json`, content: fsaPackageJson() },
|
||||
{ path: `/user/username/projects/myproject/plugin-two/node_modules/typescript-fsa/index.d.ts`, content: fsaIndex() },
|
||||
{ path: `/user/username/projects/myproject/plugin-one/tsconfig.json`, content: pluginOneConfig() },
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/plugin-one/index.ts`,
|
||||
path: `/user/username/projects/myproject/plugin-one/index.ts`,
|
||||
content: `${pluginOneIndex()}
|
||||
${pluginOneAction()}`
|
||||
},
|
||||
{ path: `${ts.tscWatch.projectRoot}/plugin-one/node_modules/typescript-fsa/package.json`, content: fsaPackageJson() },
|
||||
{ path: `${ts.tscWatch.projectRoot}/plugin-one/node_modules/typescript-fsa/index.d.ts`, content: fsaIndex() },
|
||||
{ path: `/temp/yarn/data/link/plugin-two`, symLink: `${ts.tscWatch.projectRoot}/plugin-two` },
|
||||
{ path: `${ts.tscWatch.projectRoot}/plugin-one/node_modules/plugin-two`, symLink: `/temp/yarn/data/link/plugin-two` },
|
||||
ts.tscWatch.libFile
|
||||
{ path: `/user/username/projects/myproject/plugin-one/node_modules/typescript-fsa/package.json`, content: fsaPackageJson() },
|
||||
{ path: `/user/username/projects/myproject/plugin-one/node_modules/typescript-fsa/index.d.ts`, content: fsaIndex() },
|
||||
{ path: `/temp/yarn/data/link/plugin-two`, symLink: `/user/username/projects/myproject/plugin-two` },
|
||||
{ path: `/user/username/projects/myproject/plugin-one/node_modules/plugin-two`, symLink: `/temp/yarn/data/link/plugin-two` },
|
||||
libFile
|
||||
],
|
||||
changeCaseFileTestPath: str => ts.stringContains(str, "/plugin-two"),
|
||||
});
|
||||
@@ -162,12 +164,12 @@ ${pluginOneAction()}`
|
||||
rootProject: "pkg3",
|
||||
files: [
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/pkg1/dist/index.d.ts`,
|
||||
path: `/user/username/projects/myproject/pkg1/dist/index.d.ts`,
|
||||
content: Utils.dedent`
|
||||
export * from './types';`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/pkg1/dist/types.d.ts`,
|
||||
path: `/user/username/projects/myproject/pkg1/dist/types.d.ts`,
|
||||
content: Utils.dedent`
|
||||
export declare type A = {
|
||||
id: string;
|
||||
@@ -184,7 +186,7 @@ ${pluginOneAction()}`
|
||||
}`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/pkg1/package.json`,
|
||||
path: `/user/username/projects/myproject/pkg1/package.json`,
|
||||
content: JSON.stringify({
|
||||
name: "@raymondfeng/pkg1",
|
||||
version: "1.0.0",
|
||||
@@ -193,17 +195,17 @@ ${pluginOneAction()}`
|
||||
})
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/pkg2/dist/index.d.ts`,
|
||||
path: `/user/username/projects/myproject/pkg2/dist/index.d.ts`,
|
||||
content: Utils.dedent`
|
||||
export * from './types';`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/pkg2/dist/types.d.ts`,
|
||||
path: `/user/username/projects/myproject/pkg2/dist/types.d.ts`,
|
||||
content: Utils.dedent`
|
||||
export {MetadataAccessor} from '@raymondfeng/pkg1';`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/pkg2/package.json`,
|
||||
path: `/user/username/projects/myproject/pkg2/package.json`,
|
||||
content: JSON.stringify({
|
||||
name: "@raymondfeng/pkg2",
|
||||
version: "1.0.0",
|
||||
@@ -212,18 +214,18 @@ ${pluginOneAction()}`
|
||||
})
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/pkg3/src/index.ts`,
|
||||
path: `/user/username/projects/myproject/pkg3/src/index.ts`,
|
||||
content: Utils.dedent`
|
||||
export * from './keys';`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/pkg3/src/keys.ts`,
|
||||
path: `/user/username/projects/myproject/pkg3/src/keys.ts`,
|
||||
content: Utils.dedent`
|
||||
import {MetadataAccessor} from "@raymondfeng/pkg2";
|
||||
export const ADMIN = MetadataAccessor.create<boolean>('1');`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/pkg3/tsconfig.json`,
|
||||
path: `/user/username/projects/myproject/pkg3/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
outDir: "dist",
|
||||
@@ -237,14 +239,14 @@ ${pluginOneAction()}`
|
||||
})
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/pkg2/node_modules/@raymondfeng/pkg1`,
|
||||
symLink: `${ts.tscWatch.projectRoot}/pkg1`
|
||||
path: `/user/username/projects/myproject/pkg2/node_modules/@raymondfeng/pkg1`,
|
||||
symLink: `/user/username/projects/myproject/pkg1`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/pkg3/node_modules/@raymondfeng/pkg2`,
|
||||
symLink: `${ts.tscWatch.projectRoot}/pkg2`
|
||||
path: `/user/username/projects/myproject/pkg3/node_modules/@raymondfeng/pkg2`,
|
||||
symLink: `/user/username/projects/myproject/pkg2`
|
||||
},
|
||||
ts.tscWatch.libFile
|
||||
libFile
|
||||
],
|
||||
changeCaseFileTestPath: str => ts.stringContains(str, "/pkg1"),
|
||||
});
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as Utils from "../../_namespaces/Utils";
|
||||
import { loadProjectFromFiles, verifyTsc } from "./helpers";
|
||||
|
||||
describe("unittests:: tsc:: forceConsistentCasingInFileNames::", () => {
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "forceConsistentCasingInFileNames",
|
||||
subScenario: "with relative and non relative file resolutions",
|
||||
commandLineArgs: ["/src/project/src/struct.d.ts", "--forceConsistentCasingInFileNames", "--explainFiles"],
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/project/src/struct.d.ts": Utils.dedent`
|
||||
import * as xs1 from "fp-ts/lib/Struct";
|
||||
import * as xs2 from "fp-ts/lib/struct";
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as fakes from "../../_namespaces/fakes";
|
||||
import * as vfs from "../../_namespaces/vfs";
|
||||
import * as vpath from "../../_namespaces/vpath";
|
||||
import * as Harness from "../../_namespaces/Harness";
|
||||
import { libFile, TestServerHost } from "../virtualFileSystemWithWatch";
|
||||
|
||||
export type TscCompileSystem = fakes.System & {
|
||||
writtenFiles: ts.Set<ts.Path>;
|
||||
@@ -14,11 +16,11 @@ export function compilerOptionsToConfigJson(options: ts.CompilerOptions) {
|
||||
return ts.optionMapToObject(ts.serializeCompilerOptions(options));
|
||||
}
|
||||
|
||||
export const noChangeRun: ts.TestTscEdit = {
|
||||
export const noChangeRun: TestTscEdit = {
|
||||
subScenario: "no-change-run",
|
||||
modifyFs: ts.noop
|
||||
};
|
||||
export const noChangeWithExportsDiscrepancyRun: ts.TestTscEdit = {
|
||||
export const noChangeWithExportsDiscrepancyRun: TestTscEdit = {
|
||||
...noChangeRun,
|
||||
discrepancyExplanation: () => [
|
||||
"Incremental build did not emit and has .ts as signature so exports has all imported modules/referenced files",
|
||||
@@ -26,7 +28,6 @@ export const noChangeWithExportsDiscrepancyRun: ts.TestTscEdit = {
|
||||
]
|
||||
};
|
||||
export const noChangeOnlyRuns = [noChangeRun];
|
||||
export const noChangeWithExportsDiscrepancyOnlyRuns = [noChangeWithExportsDiscrepancyRun];
|
||||
|
||||
export interface TestTscCompile extends TestTscCompileLikeBase {
|
||||
baselineSourceMap?: boolean;
|
||||
@@ -45,7 +46,7 @@ function isAnyProgram(program: ts.Program | ts.BuilderProgram | ts.ParsedCommand
|
||||
return !!(program as ts.Program | ts.BuilderProgram).getCompilerOptions;
|
||||
}
|
||||
export function commandLineCallbacks(
|
||||
sys: TscCompileSystem | ts.tscWatch.WatchedSystem,
|
||||
sys: TscCompileSystem | TestServerHost,
|
||||
originalReadCall?: ts.System["readFile"],
|
||||
): CommandLineCallbacks {
|
||||
let programs: CommandLineProgram[] | undefined;
|
||||
@@ -53,14 +54,14 @@ export function commandLineCallbacks(
|
||||
return {
|
||||
cb: program => {
|
||||
if (isAnyProgram(program)) {
|
||||
ts.baselineBuildInfo(program.getCompilerOptions(), sys, originalReadCall);
|
||||
baselineBuildInfo(program.getCompilerOptions(), sys, originalReadCall);
|
||||
(programs || (programs = [])).push(ts.isBuilderProgram(program) ?
|
||||
[program.getProgram(), program] :
|
||||
[program]
|
||||
);
|
||||
}
|
||||
else {
|
||||
ts.baselineBuildInfo(program.options, sys, originalReadCall);
|
||||
baselineBuildInfo(program.options, sys, originalReadCall);
|
||||
}
|
||||
},
|
||||
getPrograms: () => {
|
||||
@@ -136,7 +137,7 @@ function makeSystemReadyForBaseline(sys: TscCompileSystem, versionToWrite?: stri
|
||||
const writtenFiles = sys.writtenFiles = new ts.Set();
|
||||
const originalWriteFile = sys.writeFile;
|
||||
sys.writeFile = (fileName, content, writeByteOrderMark) => {
|
||||
const path = ts.toPathWithSystem(sys, fileName);
|
||||
const path = toPathWithSystem(sys, fileName);
|
||||
// When buildinfo is same for two projects,
|
||||
// it gives error and doesnt write buildinfo but because buildInfo is written for one project,
|
||||
// readable baseline will be written two times for those two projects with same contents and is ok
|
||||
@@ -147,9 +148,9 @@ function makeSystemReadyForBaseline(sys: TscCompileSystem, versionToWrite?: stri
|
||||
}
|
||||
|
||||
export function createSolutionBuilderHostForBaseline(
|
||||
sys: TscCompileSystem | ts.tscWatch.WatchedSystem,
|
||||
sys: TscCompileSystem | TestServerHost,
|
||||
versionToWrite?: string,
|
||||
originalRead?: (TscCompileSystem | ts.tscWatch.WatchedSystem)["readFile"]
|
||||
originalRead?: (TscCompileSystem | TestServerHost)["readFile"]
|
||||
) {
|
||||
if (sys instanceof fakes.System) makeSystemReadyForBaseline(sys, versionToWrite);
|
||||
const { cb } = commandLineCallbacks(sys, originalRead);
|
||||
@@ -198,21 +199,97 @@ export function testTscCompile(input: TestTscCompile) {
|
||||
}
|
||||
|
||||
function additionalBaseline(sys: TscCompileSystem) {
|
||||
const { baselineSourceMap, baselineReadFileCalls, baselinePrograms, baselineDependencies } = input;
|
||||
if (baselinePrograms) {
|
||||
const { baselineSourceMap, baselineReadFileCalls, baselinePrograms: shouldBaselinePrograms, baselineDependencies } = input;
|
||||
if (shouldBaselinePrograms) {
|
||||
const baseline: string[] = [];
|
||||
ts.tscWatch.baselinePrograms(baseline, getPrograms!, ts.emptyArray, baselineDependencies);
|
||||
baselinePrograms(baseline, getPrograms!, ts.emptyArray, baselineDependencies);
|
||||
sys.write(baseline.join("\n"));
|
||||
}
|
||||
if (baselineReadFileCalls) {
|
||||
sys.write(`readFiles:: ${JSON.stringify(actualReadFileMap, /*replacer*/ undefined, " ")} `);
|
||||
}
|
||||
if (baselineSourceMap) ts.generateSourceMapBaselineFiles(sys);
|
||||
if (baselineSourceMap) generateSourceMapBaselineFiles(sys);
|
||||
actualReadFileMap = undefined;
|
||||
getPrograms = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export function baselinePrograms(baseline: string[], getPrograms: () => readonly CommandLineProgram[], oldPrograms: readonly (CommandLineProgram | undefined)[], baselineDependencies: boolean | undefined) {
|
||||
const programs = getPrograms();
|
||||
for (let i = 0; i < programs.length; i++) {
|
||||
baselineProgram(baseline, programs[i], oldPrograms[i], baselineDependencies);
|
||||
}
|
||||
return programs;
|
||||
}
|
||||
|
||||
function baselineProgram(baseline: string[], [program, builderProgram]: CommandLineProgram, oldProgram: CommandLineProgram | undefined, baselineDependencies: boolean | undefined) {
|
||||
if (program !== oldProgram?.[0]) {
|
||||
const options = program.getCompilerOptions();
|
||||
baseline.push(`Program root files: ${JSON.stringify(program.getRootFileNames())}`);
|
||||
baseline.push(`Program options: ${JSON.stringify(options)}`);
|
||||
baseline.push(`Program structureReused: ${(ts as any).StructureIsReused[program.structureIsReused]}`);
|
||||
baseline.push("Program files::");
|
||||
for (const file of program.getSourceFiles()) {
|
||||
baseline.push(file.fileName);
|
||||
}
|
||||
}
|
||||
else {
|
||||
baseline.push(`Program: Same as old program`);
|
||||
}
|
||||
baseline.push("");
|
||||
|
||||
if (!builderProgram) return;
|
||||
if (builderProgram !== oldProgram?.[1]) {
|
||||
const state = builderProgram.getState();
|
||||
const internalState = state as unknown as ts.BuilderProgramState;
|
||||
if (state.semanticDiagnosticsPerFile?.size) {
|
||||
baseline.push("Semantic diagnostics in builder refreshed for::");
|
||||
for (const file of program.getSourceFiles()) {
|
||||
if (!internalState.semanticDiagnosticsFromOldState || !internalState.semanticDiagnosticsFromOldState.has(file.resolvedPath)) {
|
||||
baseline.push(file.fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
baseline.push("No cached semantic diagnostics in the builder::");
|
||||
}
|
||||
if (internalState) {
|
||||
baseline.push("");
|
||||
if (internalState.hasCalledUpdateShapeSignature?.size) {
|
||||
baseline.push("Shape signatures in builder refreshed for::");
|
||||
internalState.hasCalledUpdateShapeSignature.forEach((path: ts.Path) => {
|
||||
const info = state.fileInfos.get(path);
|
||||
if (info?.version === info?.signature || !info?.signature) {
|
||||
baseline.push(path + " (used version)");
|
||||
}
|
||||
else if (internalState.filesChangingSignature?.has(path)) {
|
||||
baseline.push(path + " (computed .d.ts during emit)");
|
||||
}
|
||||
else {
|
||||
baseline.push(path + " (computed .d.ts)");
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
baseline.push("No shapes updated in the builder::");
|
||||
}
|
||||
}
|
||||
baseline.push("");
|
||||
if (!baselineDependencies) return;
|
||||
baseline.push("Dependencies for::");
|
||||
for (const file of builderProgram.getSourceFiles()) {
|
||||
baseline.push(`${file.fileName}:`);
|
||||
for (const depenedency of builderProgram.getAllDependencies(file)) {
|
||||
baseline.push(` ${depenedency}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
baseline.push(`BuilderProgram: Same as old builder program`);
|
||||
}
|
||||
baseline.push("");
|
||||
}
|
||||
|
||||
export function verifyTscBaseline(sys: () => { baseLine: TscCompileSystem["baseLine"]; }) {
|
||||
it(`Generates files matching the baseline`, () => {
|
||||
const { file, text } = sys().baseLine();
|
||||
@@ -248,3 +325,698 @@ export function verifyTscCompileLike<T extends VerifyTscCompileLike>(verifier: (
|
||||
export function verifyTsc(input: TestTscCompile) {
|
||||
verifyTscCompileLike(testTscCompile, input);
|
||||
}
|
||||
|
||||
export function replaceText(fs: vfs.FileSystem, path: string, oldText: string, newText: string) {
|
||||
if (!fs.statSync(path).isFile()) {
|
||||
throw new Error(`File ${path} does not exist`);
|
||||
}
|
||||
const old = fs.readFileSync(path, "utf-8");
|
||||
if (old.indexOf(oldText) < 0) {
|
||||
throw new Error(`Text "${oldText}" does not exist in file ${path}`);
|
||||
}
|
||||
const newContent = old.replace(oldText, newText);
|
||||
fs.writeFileSync(path, newContent, "utf-8");
|
||||
}
|
||||
|
||||
export function prependText(fs: vfs.FileSystem, path: string, additionalContent: string) {
|
||||
if (!fs.statSync(path).isFile()) {
|
||||
throw new Error(`File ${path} does not exist`);
|
||||
}
|
||||
const old = fs.readFileSync(path, "utf-8");
|
||||
fs.writeFileSync(path, `${additionalContent}${old}`, "utf-8");
|
||||
}
|
||||
|
||||
export function appendText(fs: vfs.FileSystem, path: string, additionalContent: string) {
|
||||
if (!fs.statSync(path).isFile()) {
|
||||
throw new Error(`File ${path} does not exist`);
|
||||
}
|
||||
const old = fs.readFileSync(path, "utf-8");
|
||||
fs.writeFileSync(path, `${old}${additionalContent}`);
|
||||
}
|
||||
|
||||
export const libContent = `${libFile.content}
|
||||
interface ReadonlyArray<T> {}
|
||||
declare const console: { log(msg: any): void; };`;
|
||||
|
||||
export const symbolLibContent = `
|
||||
interface SymbolConstructor {
|
||||
readonly species: symbol;
|
||||
readonly toStringTag: symbol;
|
||||
}
|
||||
declare var Symbol: SymbolConstructor;
|
||||
interface Symbol {
|
||||
readonly [Symbol.toStringTag]: string;
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* Load project from disk into /src folder
|
||||
*/
|
||||
export function loadProjectFromDisk(
|
||||
root: string,
|
||||
libContentToAppend?: string
|
||||
): vfs.FileSystem {
|
||||
const resolver = vfs.createResolver(Harness.IO);
|
||||
const fs = new vfs.FileSystem(/*ignoreCase*/ true, {
|
||||
files: {
|
||||
["/src"]: new vfs.Mount(vpath.resolve(Harness.IO.getWorkspaceRoot(), root), resolver)
|
||||
},
|
||||
cwd: "/",
|
||||
meta: { defaultLibLocation: "/lib" },
|
||||
});
|
||||
addLibAndMakeReadonly(fs, libContentToAppend);
|
||||
return fs;
|
||||
}
|
||||
|
||||
/**
|
||||
* All the files must be in /src
|
||||
*/
|
||||
export function loadProjectFromFiles(
|
||||
files: vfs.FileSet,
|
||||
libContentToAppend?: string
|
||||
): vfs.FileSystem {
|
||||
const fs = new vfs.FileSystem(/*ignoreCase*/ true, {
|
||||
files,
|
||||
cwd: "/",
|
||||
meta: { defaultLibLocation: "/lib" },
|
||||
});
|
||||
addLibAndMakeReadonly(fs, libContentToAppend);
|
||||
return fs;
|
||||
}
|
||||
|
||||
function addLibAndMakeReadonly(fs: vfs.FileSystem, libContentToAppend?: string) {
|
||||
fs.mkdirSync("/lib");
|
||||
fs.writeFileSync("/lib/lib.d.ts", libContentToAppend ? `${libContent}${libContentToAppend}` : libContent);
|
||||
fs.makeReadonly();
|
||||
}
|
||||
|
||||
export function generateSourceMapBaselineFiles(sys: ts.System & { writtenFiles: ts.ReadonlyCollection<ts.Path>; }) {
|
||||
const mapFileNames = ts.mapDefinedIterator(sys.writtenFiles.keys(), f => f.endsWith(".map") ? f : undefined);
|
||||
while (true) {
|
||||
const result = mapFileNames.next();
|
||||
if (result.done) break;
|
||||
const mapFile = result.value;
|
||||
const text = Harness.SourceMapRecorder.getSourceMapRecordWithSystem(sys, mapFile);
|
||||
sys.writeFile(`${mapFile}.baseline.txt`, text);
|
||||
}
|
||||
}
|
||||
|
||||
function generateBundleFileSectionInfo(sys: ts.System, originalReadCall: ts.System["readFile"], baselineRecorder: Harness.Compiler.WriterAggregator, bundleFileInfo: ts.BundleFileInfo | undefined, outFile: string | undefined) {
|
||||
if (!ts.length(bundleFileInfo && bundleFileInfo.sections) && !outFile) return; // Nothing to baseline
|
||||
|
||||
const content = outFile && sys.fileExists(outFile) ? originalReadCall.call(sys, outFile, "utf8")! : "";
|
||||
baselineRecorder.WriteLine("======================================================================");
|
||||
baselineRecorder.WriteLine(`File:: ${outFile}`);
|
||||
for (const section of bundleFileInfo ? bundleFileInfo.sections : ts.emptyArray) {
|
||||
baselineRecorder.WriteLine("----------------------------------------------------------------------");
|
||||
writeSectionHeader(section);
|
||||
if (section.kind !== ts.BundleFileSectionKind.Prepend) {
|
||||
writeTextOfSection(section.pos, section.end);
|
||||
}
|
||||
else if (section.texts.length > 0) {
|
||||
ts.Debug.assert(section.pos === ts.first(section.texts).pos);
|
||||
ts.Debug.assert(section.end === ts.last(section.texts).end);
|
||||
for (const text of section.texts) {
|
||||
baselineRecorder.WriteLine(">>--------------------------------------------------------------------");
|
||||
writeSectionHeader(text);
|
||||
writeTextOfSection(text.pos, text.end);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ts.Debug.assert(section.pos === section.end);
|
||||
}
|
||||
}
|
||||
baselineRecorder.WriteLine("======================================================================");
|
||||
|
||||
function writeTextOfSection(pos: number, end: number) {
|
||||
const textLines = content.substring(pos, end).split(/\r?\n/);
|
||||
for (const line of textLines) {
|
||||
baselineRecorder.WriteLine(line);
|
||||
}
|
||||
}
|
||||
|
||||
function writeSectionHeader(section: ts.BundleFileSection) {
|
||||
baselineRecorder.WriteLine(`${section.kind}: (${section.pos}-${section.end})${section.data ? ":: " + section.data : ""}${section.kind === ts.BundleFileSectionKind.Prepend ? " texts:: " + section.texts.length : ""}`);
|
||||
}
|
||||
}
|
||||
|
||||
type ReadableProgramBuildInfoDiagnostic = string | [string, readonly ts.ReusableDiagnostic[]];
|
||||
type ReadableBuilderFileEmit = string & { __readableBuilderFileEmit: any; };
|
||||
type ReadableProgramBuilderInfoFilePendingEmit = [original: string | [string], emitKind: ReadableBuilderFileEmit];
|
||||
type ReadableProgramBuildInfoEmitSignature = string | [string, ts.EmitSignature | []];
|
||||
type ReadableProgramBuildInfoFileInfo<T> = Omit<ts.BuilderState.FileInfo, "impliedFormat"> & {
|
||||
impliedFormat: string | undefined;
|
||||
original: T | undefined;
|
||||
};
|
||||
type ReadableProgramMultiFileEmitBuildInfo = Omit<ts.ProgramMultiFileEmitBuildInfo,
|
||||
"fileIdsList" | "fileInfos" |
|
||||
"referencedMap" | "exportedModulesMap" | "semanticDiagnosticsPerFile" |
|
||||
"affectedFilesPendingEmit" | "changeFileSet" | "emitSignatures"
|
||||
> & {
|
||||
fileNamesList: readonly (readonly string[])[] | undefined;
|
||||
fileInfos: ts.MapLike<ReadableProgramBuildInfoFileInfo<ts.ProgramMultiFileEmitBuildInfoFileInfo>>;
|
||||
referencedMap: ts.MapLike<string[]> | undefined;
|
||||
exportedModulesMap: ts.MapLike<string[]> | undefined;
|
||||
semanticDiagnosticsPerFile: readonly ReadableProgramBuildInfoDiagnostic[] | undefined;
|
||||
affectedFilesPendingEmit: readonly ReadableProgramBuilderInfoFilePendingEmit[] | undefined;
|
||||
changeFileSet: readonly string[] | undefined;
|
||||
emitSignatures: readonly ReadableProgramBuildInfoEmitSignature[] | undefined;
|
||||
};
|
||||
type ReadableProgramBuildInfoBundlePendingEmit = [emitKind: ReadableBuilderFileEmit, original: ts.ProgramBuildInfoBundlePendingEmit];
|
||||
type ReadableProgramBundleEmitBuildInfo = Omit<ts.ProgramBundleEmitBuildInfo, "fileInfos" | "pendingEmit"> & {
|
||||
fileInfos: ts.MapLike<string | ReadableProgramBuildInfoFileInfo<ts.BuilderState.FileInfo>>;
|
||||
pendingEmit: ReadableProgramBuildInfoBundlePendingEmit | undefined;
|
||||
};
|
||||
|
||||
type ReadableProgramBuildInfo = ReadableProgramMultiFileEmitBuildInfo | ReadableProgramBundleEmitBuildInfo;
|
||||
|
||||
function isReadableProgramBundleEmitBuildInfo(info: ReadableProgramBuildInfo | undefined): info is ReadableProgramBundleEmitBuildInfo {
|
||||
return !!info && !!ts.outFile(info.options || {});
|
||||
}
|
||||
type ReadableBuildInfo = Omit<ts.BuildInfo, "program"> & { program: ReadableProgramBuildInfo | undefined; size: number; };
|
||||
function generateBuildInfoProgramBaseline(sys: ts.System, buildInfoPath: string, buildInfo: ts.BuildInfo) {
|
||||
let program: ReadableProgramBuildInfo | undefined;
|
||||
let fileNamesList: string[][] | undefined;
|
||||
if (buildInfo.program && ts.isProgramBundleEmitBuildInfo(buildInfo.program)) {
|
||||
const fileInfos: ReadableProgramBundleEmitBuildInfo["fileInfos"] = {};
|
||||
buildInfo.program?.fileInfos?.forEach((fileInfo, index) =>
|
||||
fileInfos[toFileName(index + 1 as ts.ProgramBuildInfoFileId)] = ts.isString(fileInfo) ?
|
||||
fileInfo :
|
||||
toReadableFileInfo(fileInfo, ts.identity)
|
||||
);
|
||||
const pendingEmit = buildInfo.program.pendingEmit;
|
||||
program = {
|
||||
...buildInfo.program,
|
||||
fileInfos,
|
||||
pendingEmit: pendingEmit === undefined ?
|
||||
undefined :
|
||||
[
|
||||
toReadableBuilderFileEmit(ts.toProgramEmitPending(pendingEmit, buildInfo.program.options)),
|
||||
pendingEmit
|
||||
],
|
||||
};
|
||||
}
|
||||
else if (buildInfo.program) {
|
||||
const fileInfos: ReadableProgramMultiFileEmitBuildInfo["fileInfos"] = {};
|
||||
buildInfo.program?.fileInfos?.forEach((fileInfo, index) => fileInfos[toFileName(index + 1 as ts.ProgramBuildInfoFileId)] = toReadableFileInfo(fileInfo, ts.toBuilderStateFileInfoForMultiEmit));
|
||||
fileNamesList = buildInfo.program.fileIdsList?.map(fileIdsListId => fileIdsListId.map(toFileName));
|
||||
const fullEmitForOptions = buildInfo.program.affectedFilesPendingEmit ? ts.getBuilderFileEmit(buildInfo.program.options || {}) : undefined;
|
||||
program = buildInfo.program && {
|
||||
fileNames: buildInfo.program.fileNames,
|
||||
fileNamesList,
|
||||
fileInfos: buildInfo.program.fileInfos ? fileInfos : undefined!,
|
||||
options: buildInfo.program.options,
|
||||
referencedMap: toMapOfReferencedSet(buildInfo.program.referencedMap),
|
||||
exportedModulesMap: toMapOfReferencedSet(buildInfo.program.exportedModulesMap),
|
||||
semanticDiagnosticsPerFile: buildInfo.program.semanticDiagnosticsPerFile?.map(d =>
|
||||
ts.isNumber(d) ?
|
||||
toFileName(d) :
|
||||
[toFileName(d[0]), d[1]]
|
||||
),
|
||||
affectedFilesPendingEmit: buildInfo.program.affectedFilesPendingEmit?.map(value => toReadableProgramBuilderInfoFilePendingEmit(value, fullEmitForOptions!)),
|
||||
changeFileSet: buildInfo.program.changeFileSet?.map(toFileName),
|
||||
emitSignatures: buildInfo.program.emitSignatures?.map(s =>
|
||||
ts.isNumber(s) ?
|
||||
toFileName(s) :
|
||||
[toFileName(s[0]), s[1]]
|
||||
),
|
||||
latestChangedDtsFile: buildInfo.program.latestChangedDtsFile,
|
||||
};
|
||||
}
|
||||
const version = buildInfo.version === ts.version ? fakes.version : buildInfo.version;
|
||||
const result: ReadableBuildInfo = {
|
||||
// Baseline fixed order for bundle
|
||||
bundle: buildInfo.bundle && {
|
||||
...buildInfo.bundle,
|
||||
js: buildInfo.bundle.js && {
|
||||
sections: buildInfo.bundle.js.sections,
|
||||
hash: buildInfo.bundle.js.hash,
|
||||
mapHash: buildInfo.bundle.js.mapHash,
|
||||
sources: buildInfo.bundle.js.sources,
|
||||
},
|
||||
dts: buildInfo.bundle.dts && {
|
||||
sections: buildInfo.bundle.dts.sections,
|
||||
hash: buildInfo.bundle.dts.hash,
|
||||
mapHash: buildInfo.bundle.dts.mapHash,
|
||||
sources: buildInfo.bundle.dts.sources,
|
||||
},
|
||||
},
|
||||
program,
|
||||
version,
|
||||
size: ts.getBuildInfoText({ ...buildInfo, version }).length,
|
||||
};
|
||||
// For now its just JSON.stringify
|
||||
sys.writeFile(`${buildInfoPath}.readable.baseline.txt`, JSON.stringify(result, /*replacer*/ undefined, 2));
|
||||
|
||||
function toFileName(fileId: ts.ProgramBuildInfoFileId) {
|
||||
return buildInfo.program!.fileNames[fileId - 1];
|
||||
}
|
||||
|
||||
function toFileNames(fileIdsListId: ts.ProgramBuildInfoFileIdListId) {
|
||||
return fileNamesList![fileIdsListId - 1];
|
||||
}
|
||||
|
||||
function toReadableFileInfo<T>(original: T, toFileInfo: (fileInfo: T) => ts.BuilderState.FileInfo): ReadableProgramBuildInfoFileInfo<T> {
|
||||
const info = toFileInfo(original);
|
||||
return {
|
||||
original: ts.isString(original) ? undefined : original,
|
||||
...info,
|
||||
impliedFormat: info.impliedFormat && ts.getNameOfCompilerOptionValue(info.impliedFormat, ts.moduleOptionDeclaration.type),
|
||||
};
|
||||
}
|
||||
|
||||
function toMapOfReferencedSet(referenceMap: ts.ProgramBuildInfoReferencedMap | undefined): ts.MapLike<string[]> | undefined {
|
||||
if (!referenceMap) return undefined;
|
||||
const result: ts.MapLike<string[]> = {};
|
||||
for (const [fileNamesKey, fileNamesListKey] of referenceMap) {
|
||||
result[toFileName(fileNamesKey)] = toFileNames(fileNamesListKey);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function toReadableProgramBuilderInfoFilePendingEmit(value: ts.ProgramBuilderInfoFilePendingEmit, fullEmitForOptions: ts.BuilderFileEmit): ReadableProgramBuilderInfoFilePendingEmit {
|
||||
return [
|
||||
ts.isNumber(value) ? toFileName(value) : [toFileName(value[0])],
|
||||
toReadableBuilderFileEmit(ts.toBuilderFileEmit(value, fullEmitForOptions)),
|
||||
];
|
||||
}
|
||||
|
||||
function toReadableBuilderFileEmit(emit: ts.BuilderFileEmit | undefined): ReadableBuilderFileEmit {
|
||||
let result = "";
|
||||
if (emit) {
|
||||
if (emit & ts.BuilderFileEmit.Js) addFlags("Js");
|
||||
if (emit & ts.BuilderFileEmit.JsMap) addFlags("JsMap");
|
||||
if (emit & ts.BuilderFileEmit.JsInlineMap) addFlags("JsInlineMap");
|
||||
if (emit & ts.BuilderFileEmit.Dts) addFlags("Dts");
|
||||
if (emit & ts.BuilderFileEmit.DtsMap) addFlags("DtsMap");
|
||||
}
|
||||
return (result || "None") as ReadableBuilderFileEmit;
|
||||
function addFlags(flag: string) {
|
||||
result = result ? `${result} | ${flag}` : flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function toPathWithSystem(sys: ts.System, fileName: string): ts.Path {
|
||||
return ts.toPath(fileName, sys.getCurrentDirectory(), ts.createGetCanonicalFileName(sys.useCaseSensitiveFileNames));
|
||||
}
|
||||
|
||||
export function baselineBuildInfo(
|
||||
options: ts.CompilerOptions,
|
||||
sys: TscCompileSystem | TestServerHost,
|
||||
originalReadCall?: ts.System["readFile"],
|
||||
) {
|
||||
const buildInfoPath = ts.getTsBuildInfoEmitOutputFilePath(options);
|
||||
if (!buildInfoPath || !sys.writtenFiles!.has(toPathWithSystem(sys, buildInfoPath))) return;
|
||||
if (!sys.fileExists(buildInfoPath)) return;
|
||||
|
||||
const buildInfo = ts.getBuildInfo(buildInfoPath, (originalReadCall || sys.readFile).call(sys, buildInfoPath, "utf8")!);
|
||||
if (!buildInfo) return sys.writeFile(`${buildInfoPath}.baseline.txt`, "Error reading valid buildinfo file");
|
||||
generateBuildInfoProgramBaseline(sys, buildInfoPath, buildInfo);
|
||||
|
||||
if (!ts.outFile(options)) return;
|
||||
const { jsFilePath, declarationFilePath } = ts.getOutputPathsForBundle(options, /*forceDts*/ false);
|
||||
const bundle = buildInfo.bundle;
|
||||
if (!bundle || (!ts.length(bundle.js && bundle.js.sections) && !ts.length(bundle.dts && bundle.dts.sections))) return;
|
||||
|
||||
// Write the baselines:
|
||||
const baselineRecorder = new Harness.Compiler.WriterAggregator();
|
||||
generateBundleFileSectionInfo(sys, originalReadCall || sys.readFile, baselineRecorder, bundle.js, jsFilePath);
|
||||
generateBundleFileSectionInfo(sys, originalReadCall || sys.readFile, baselineRecorder, bundle.dts, declarationFilePath);
|
||||
baselineRecorder.Close();
|
||||
const text = baselineRecorder.lines.join("\r\n");
|
||||
sys.writeFile(`${buildInfoPath}.baseline.txt`, text);
|
||||
}
|
||||
interface VerifyTscEditDiscrepanciesInput {
|
||||
index: number;
|
||||
scenario: TestTscCompile["scenario"];
|
||||
subScenario: TestTscCompile["subScenario"];
|
||||
baselines: string[] | undefined;
|
||||
commandLineArgs: TestTscCompile["commandLineArgs"];
|
||||
modifyFs: TestTscCompile["modifyFs"];
|
||||
editFs: TestTscEdit["modifyFs"];
|
||||
baseFs: vfs.FileSystem;
|
||||
newSys: TscCompileSystem;
|
||||
discrepancyExplanation: TestTscEdit["discrepancyExplanation"];
|
||||
}
|
||||
function verifyTscEditDiscrepancies({
|
||||
index, scenario, subScenario, commandLineArgs,
|
||||
discrepancyExplanation, baselines,
|
||||
modifyFs, editFs, baseFs, newSys
|
||||
}: VerifyTscEditDiscrepanciesInput): string[] | undefined {
|
||||
const sys = testTscCompile({
|
||||
scenario,
|
||||
subScenario,
|
||||
fs: () => baseFs.makeReadonly(),
|
||||
commandLineArgs,
|
||||
modifyFs: fs => {
|
||||
if (modifyFs) modifyFs(fs);
|
||||
editFs(fs);
|
||||
},
|
||||
disableUseFileVersionAsSignature: true,
|
||||
});
|
||||
let headerAdded = false;
|
||||
for (const outputFile of ts.arrayFrom(sys.writtenFiles.keys())) {
|
||||
const cleanBuildText = sys.readFile(outputFile);
|
||||
const incrementalBuildText = newSys.readFile(outputFile);
|
||||
if (ts.isBuildInfoFile(outputFile)) {
|
||||
// Check only presence and absence and not text as we will do that for readable baseline
|
||||
if (!sys.fileExists(`${outputFile}.readable.baseline.txt`)) addBaseline(`Readable baseline not present in clean build:: File:: ${outputFile}`);
|
||||
if (!newSys.fileExists(`${outputFile}.readable.baseline.txt`)) addBaseline(`Readable baseline not present in incremental build:: File:: ${outputFile}`);
|
||||
verifyPresenceAbsence(incrementalBuildText, cleanBuildText, `Incremental and clean tsbuildinfo file presence differs:: File:: ${outputFile}`);
|
||||
}
|
||||
else if (!ts.fileExtensionIs(outputFile, ".tsbuildinfo.readable.baseline.txt")) {
|
||||
verifyTextEqual(incrementalBuildText, cleanBuildText, `File: ${outputFile}`);
|
||||
}
|
||||
else if (incrementalBuildText !== cleanBuildText) {
|
||||
// Verify build info without affectedFilesPendingEmit
|
||||
const { buildInfo: incrementalBuildInfo, readableBuildInfo: incrementalReadableBuildInfo } = getBuildInfoForIncrementalCorrectnessCheck(incrementalBuildText);
|
||||
const { buildInfo: cleanBuildInfo, readableBuildInfo: cleanReadableBuildInfo } = getBuildInfoForIncrementalCorrectnessCheck(cleanBuildText);
|
||||
verifyTextEqual(incrementalBuildInfo, cleanBuildInfo, `TsBuild info text without affectedFilesPendingEmit:: ${outputFile}::`);
|
||||
// Verify file info sigantures
|
||||
verifyMapLike(
|
||||
incrementalReadableBuildInfo?.program?.fileInfos as ReadableProgramMultiFileEmitBuildInfo["fileInfos"],
|
||||
cleanReadableBuildInfo?.program?.fileInfos as ReadableProgramMultiFileEmitBuildInfo["fileInfos"],
|
||||
(key, incrementalFileInfo, cleanFileInfo) => {
|
||||
if (incrementalFileInfo.signature !== cleanFileInfo.signature && incrementalFileInfo.signature !== incrementalFileInfo.version) {
|
||||
return [
|
||||
`Incremental signature is neither dts signature nor file version for File:: ${key}`,
|
||||
`Incremental:: ${JSON.stringify(incrementalFileInfo, /*replacer*/ undefined, 2)}`,
|
||||
`Clean:: ${JSON.stringify(cleanFileInfo, /*replacer*/ undefined, 2)}`
|
||||
];
|
||||
}
|
||||
},
|
||||
`FileInfos:: File:: ${outputFile}`
|
||||
);
|
||||
if (!isReadableProgramBundleEmitBuildInfo(incrementalReadableBuildInfo?.program)) {
|
||||
ts.Debug.assert(!isReadableProgramBundleEmitBuildInfo(cleanReadableBuildInfo?.program));
|
||||
// Verify exportedModulesMap
|
||||
verifyMapLike(
|
||||
incrementalReadableBuildInfo?.program?.exportedModulesMap,
|
||||
cleanReadableBuildInfo?.program?.exportedModulesMap,
|
||||
(key, incrementalReferenceSet, cleanReferenceSet) => {
|
||||
if (!ts.arrayIsEqualTo(incrementalReferenceSet, cleanReferenceSet) && !ts.arrayIsEqualTo(incrementalReferenceSet, (incrementalReadableBuildInfo!.program! as ReadableProgramMultiFileEmitBuildInfo).referencedMap![key])) {
|
||||
return [
|
||||
`Incremental Reference set is neither from dts nor files reference map for File:: ${key}::`,
|
||||
`Incremental:: ${JSON.stringify(incrementalReferenceSet, /*replacer*/ undefined, 2)}`,
|
||||
`Clean:: ${JSON.stringify(cleanReferenceSet, /*replacer*/ undefined, 2)}`,
|
||||
`IncrementalReferenceMap:: ${JSON.stringify((incrementalReadableBuildInfo!.program! as ReadableProgramMultiFileEmitBuildInfo).referencedMap![key], /*replacer*/ undefined, 2)}`,
|
||||
`CleanReferenceMap:: ${JSON.stringify((cleanReadableBuildInfo!.program! as ReadableProgramMultiFileEmitBuildInfo).referencedMap![key], /*replacer*/ undefined, 2)}`,
|
||||
];
|
||||
}
|
||||
},
|
||||
`exportedModulesMap:: File:: ${outputFile}`
|
||||
);
|
||||
// Verify that incrementally pending affected file emit are in clean build since clean build can contain more files compared to incremental depending of noEmitOnError option
|
||||
if (incrementalReadableBuildInfo?.program?.affectedFilesPendingEmit) {
|
||||
if (cleanReadableBuildInfo?.program?.affectedFilesPendingEmit === undefined) {
|
||||
addBaseline(
|
||||
`Incremental build contains affectedFilesPendingEmit, clean build does not have it: ${outputFile}::`,
|
||||
`Incremental buildInfoText:: ${incrementalBuildText}`,
|
||||
`Clean buildInfoText:: ${cleanBuildText}`
|
||||
);
|
||||
}
|
||||
let expectedIndex = 0;
|
||||
incrementalReadableBuildInfo.program.affectedFilesPendingEmit.forEach(([actualFileOrArray]) => {
|
||||
const actualFile = ts.isString(actualFileOrArray) ? actualFileOrArray : actualFileOrArray[0];
|
||||
expectedIndex = ts.findIndex(
|
||||
(cleanReadableBuildInfo!.program! as ReadableProgramMultiFileEmitBuildInfo).affectedFilesPendingEmit,
|
||||
([expectedFileOrArray]) => actualFile === (ts.isString(expectedFileOrArray) ? expectedFileOrArray : expectedFileOrArray[0]),
|
||||
expectedIndex
|
||||
);
|
||||
if (expectedIndex === -1) {
|
||||
addBaseline(
|
||||
`Incremental build contains ${actualFile} file as pending emit, clean build does not have it: ${outputFile}::`,
|
||||
`Incremental buildInfoText:: ${incrementalBuildText}`,
|
||||
`Clean buildInfoText:: ${cleanBuildText}`
|
||||
);
|
||||
}
|
||||
expectedIndex++;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!headerAdded && discrepancyExplanation) addBaseline("*** Supplied discrepancy explanation but didnt file any difference");
|
||||
return baselines;
|
||||
|
||||
function verifyTextEqual(incrementalText: string | undefined, cleanText: string | undefined, message: string) {
|
||||
if (incrementalText !== cleanText) writeNotEqual(incrementalText, cleanText, message);
|
||||
}
|
||||
|
||||
function verifyMapLike<T>(incremental: ts.MapLike<T> | undefined, clean: ts.MapLike<T> | undefined, verifyValue: (key: string, incrementalValue: T, cleanValue: T) => string[] | undefined, message: string) {
|
||||
verifyPresenceAbsence(incremental, clean, `Incremental and clean do not match:: ${message}`);
|
||||
if (!incremental || !clean) return;
|
||||
const incrementalMap = new ts.Map(ts.getEntries(incremental));
|
||||
const cleanMap = new ts.Map(ts.getEntries(clean));
|
||||
if (incrementalMap.size !== cleanMap.size) {
|
||||
addBaseline(
|
||||
`Incremental and clean size of maps do not match:: ${message}`,
|
||||
`Incremental: ${JSON.stringify(incremental, /*replacer*/ undefined, 2)}`,
|
||||
`Clean: ${JSON.stringify(clean, /*replacer*/ undefined, 2)}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
cleanMap.forEach((cleanValue, key) => {
|
||||
const incrementalValue = incrementalMap.get(key);
|
||||
if (!incrementalValue) {
|
||||
addBaseline(
|
||||
`Incremental does not contain ${key} which is present in clean:: ${message}`,
|
||||
`Incremental: ${JSON.stringify(incremental, /*replacer*/ undefined, 2)}`,
|
||||
`Clean: ${JSON.stringify(clean, /*replacer*/ undefined, 2)}`,
|
||||
);
|
||||
}
|
||||
else {
|
||||
const result = verifyValue(key, incrementalMap.get(key)!, cleanValue);
|
||||
if (result) addBaseline(...result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function verifyPresenceAbsence<T>(actual: T | undefined, expected: T | undefined, message: string) {
|
||||
if (expected === undefined) {
|
||||
if (actual === undefined) return;
|
||||
}
|
||||
else {
|
||||
if (actual !== undefined) return;
|
||||
}
|
||||
writeNotEqual(actual, expected, message);
|
||||
}
|
||||
|
||||
function writeNotEqual<T>(actual: T | undefined, expected: T | undefined, message: string) {
|
||||
addBaseline(
|
||||
message,
|
||||
"CleanBuild:",
|
||||
ts.isString(expected) ? expected : JSON.stringify(expected),
|
||||
"IncrementalBuild:",
|
||||
ts.isString(actual) ? actual : JSON.stringify(actual),
|
||||
);
|
||||
}
|
||||
|
||||
function addBaseline(...text: string[]) {
|
||||
if (!baselines || !headerAdded) {
|
||||
(baselines ||= []).push(`${index}:: ${subScenario}`, ...(discrepancyExplanation?.()|| ["*** Needs explanation"]));
|
||||
headerAdded = true;
|
||||
}
|
||||
baselines.push(...text);
|
||||
}
|
||||
}
|
||||
|
||||
function getBuildInfoForIncrementalCorrectnessCheck(text: string | undefined): {
|
||||
buildInfo: string | undefined;
|
||||
readableBuildInfo?: ReadableBuildInfo;
|
||||
} {
|
||||
if (!text) return { buildInfo: text };
|
||||
const readableBuildInfo = JSON.parse(text) as ReadableBuildInfo;
|
||||
let sanitizedFileInfos: ts.MapLike<string | Omit<ReadableProgramBuildInfoFileInfo<ts.ProgramMultiFileEmitBuildInfoFileInfo> | ReadableProgramBuildInfoFileInfo<ts.BuilderState.FileInfo>, "signature" | "original"> & { signature: undefined; original: undefined; }> | undefined;
|
||||
if (readableBuildInfo.program?.fileInfos) {
|
||||
sanitizedFileInfos = {};
|
||||
for (const id in readableBuildInfo.program.fileInfos) {
|
||||
if (ts.hasProperty(readableBuildInfo.program.fileInfos, id)) {
|
||||
const info = readableBuildInfo.program.fileInfos[id];
|
||||
sanitizedFileInfos[id] = ts.isString(info) ? info : { ...info, signature: undefined, original: undefined };
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
buildInfo: JSON.stringify({
|
||||
...readableBuildInfo,
|
||||
program: readableBuildInfo.program && {
|
||||
...readableBuildInfo.program,
|
||||
fileNames: undefined,
|
||||
fileNamesList: undefined,
|
||||
fileInfos: sanitizedFileInfos,
|
||||
// Ignore noEmit since that shouldnt be reason to emit the tsbuild info and presence of it in the buildinfo file does not matter
|
||||
options: { ...readableBuildInfo.program.options, noEmit: undefined },
|
||||
exportedModulesMap: undefined,
|
||||
affectedFilesPendingEmit: undefined,
|
||||
latestChangedDtsFile: readableBuildInfo.program.latestChangedDtsFile ? "FakeFileName" : undefined,
|
||||
},
|
||||
size: undefined, // Size doesnt need to be equal
|
||||
}, /*replacer*/ undefined, 2),
|
||||
readableBuildInfo,
|
||||
};
|
||||
}
|
||||
|
||||
export interface TestTscEdit {
|
||||
modifyFs: (fs: vfs.FileSystem) => void;
|
||||
subScenario: string;
|
||||
commandLineArgs?: readonly string[];
|
||||
/** An array of lines to be printed in order when a discrepancy is detected */
|
||||
discrepancyExplanation?: () => readonly string[];
|
||||
}
|
||||
|
||||
export interface VerifyTscWithEditsInput extends TestTscCompile {
|
||||
edits: TestTscEdit[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify non watch tsc invokcation after each edit
|
||||
*/
|
||||
export function verifyTscWithEdits({
|
||||
subScenario, fs, scenario, commandLineArgs,
|
||||
baselineSourceMap, modifyFs, baselineReadFileCalls, baselinePrograms,
|
||||
edits
|
||||
}: VerifyTscWithEditsInput) {
|
||||
describe(`tsc ${commandLineArgs.join(" ")} ${scenario}:: ${subScenario} serializedEdits`, () => {
|
||||
let sys: TscCompileSystem;
|
||||
let baseFs: vfs.FileSystem;
|
||||
let editsSys: TscCompileSystem[];
|
||||
before(() => {
|
||||
ts.Debug.assert(!!edits.length, `${scenario}/${subScenario}:: No incremental scenarios, you probably want to use verifyTsc instead.`);
|
||||
baseFs = fs().makeReadonly();
|
||||
sys = testTscCompile({
|
||||
scenario,
|
||||
subScenario,
|
||||
fs: () => baseFs,
|
||||
commandLineArgs,
|
||||
modifyFs,
|
||||
baselineSourceMap,
|
||||
baselineReadFileCalls,
|
||||
baselinePrograms
|
||||
});
|
||||
edits.forEach((
|
||||
{ modifyFs, subScenario: editScenario, commandLineArgs: editCommandLineArgs },
|
||||
index
|
||||
) => {
|
||||
(editsSys || (editsSys = [])).push(testTscCompile({
|
||||
scenario,
|
||||
subScenario: editScenario || subScenario,
|
||||
diffWithInitial: true,
|
||||
fs: () => index === 0 ? sys.vfs : editsSys[index - 1].vfs,
|
||||
commandLineArgs: editCommandLineArgs || commandLineArgs,
|
||||
modifyFs,
|
||||
baselineSourceMap,
|
||||
baselineReadFileCalls,
|
||||
baselinePrograms
|
||||
}));
|
||||
});
|
||||
});
|
||||
after(() => {
|
||||
baseFs = undefined!;
|
||||
sys = undefined!;
|
||||
editsSys = undefined!;
|
||||
});
|
||||
verifyTscBaseline(() => ({
|
||||
baseLine: () => {
|
||||
const { file, text } = sys.baseLine();
|
||||
const texts: string[] = [text];
|
||||
editsSys.forEach((sys, index) => {
|
||||
const incrementalScenario = edits[index];
|
||||
texts.push("");
|
||||
texts.push(`Change:: ${incrementalScenario.subScenario}`);
|
||||
texts.push(sys.baseLine().text);
|
||||
});
|
||||
return { file, text: texts.join("\r\n") };
|
||||
}
|
||||
}));
|
||||
it("tsc invocation after edit and clean build correctness", () => {
|
||||
let baselines: string[] | undefined;
|
||||
for (let index = 0; index < edits.length; index++) {
|
||||
baselines = verifyTscEditDiscrepancies({
|
||||
index,
|
||||
scenario,
|
||||
subScenario: edits[index].subScenario,
|
||||
baselines,
|
||||
baseFs,
|
||||
newSys: editsSys[index],
|
||||
commandLineArgs: edits[index].commandLineArgs || commandLineArgs,
|
||||
discrepancyExplanation: edits[index].discrepancyExplanation,
|
||||
editFs: fs => {
|
||||
for (let i = 0; i <= index; i++) {
|
||||
edits[i].modifyFs(fs);
|
||||
}
|
||||
},
|
||||
modifyFs
|
||||
});
|
||||
}
|
||||
Harness.Baseline.runBaseline(
|
||||
`${ts.isBuild(commandLineArgs) ? "tsbuild" : "tsc"}/${scenario}/${subScenario.split(" ").join("-")}-discrepancies.js`,
|
||||
baselines ? baselines.join("\r\n") : null // eslint-disable-line no-null/no-null
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function enableStrict(fs: vfs.FileSystem, path: string) {
|
||||
replaceText(fs, path, `"strict": false`, `"strict": true`);
|
||||
}
|
||||
|
||||
export function addTestPrologue(fs: vfs.FileSystem, path: string, prologue: string) {
|
||||
prependText(fs, path, `${prologue}
|
||||
`);
|
||||
}
|
||||
|
||||
export function addShebang(fs: vfs.FileSystem, project: string, file: string) {
|
||||
prependText(fs, `src/${project}/${file}.ts`, `#!someshebang ${project} ${file}
|
||||
`);
|
||||
}
|
||||
|
||||
export function restContent(project: string, file: string) {
|
||||
return `function for${project}${file}Rest() {
|
||||
const { b, ...rest } = { a: 10, b: 30, yy: 30 };
|
||||
}`;
|
||||
}
|
||||
|
||||
function nonrestContent(project: string, file: string) {
|
||||
return `function for${project}${file}Rest() { }`;
|
||||
}
|
||||
|
||||
export function addRest(fs: vfs.FileSystem, project: string, file: string) {
|
||||
appendText(fs, `src/${project}/${file}.ts`, restContent(project, file));
|
||||
}
|
||||
|
||||
export function removeRest(fs: vfs.FileSystem, project: string, file: string) {
|
||||
replaceText(fs, `src/${project}/${file}.ts`, restContent(project, file), nonrestContent(project, file));
|
||||
}
|
||||
|
||||
export function addStubFoo(fs: vfs.FileSystem, project: string, file: string) {
|
||||
appendText(fs, `src/${project}/${file}.ts`, nonrestContent(project, file));
|
||||
}
|
||||
|
||||
export function changeStubToRest(fs: vfs.FileSystem, project: string, file: string) {
|
||||
replaceText(fs, `src/${project}/${file}.ts`, nonrestContent(project, file), restContent(project, file));
|
||||
}
|
||||
|
||||
export function addSpread(fs: vfs.FileSystem, project: string, file: string) {
|
||||
const path = `src/${project}/${file}.ts`;
|
||||
const content = fs.readFileSync(path, "utf8");
|
||||
fs.writeFileSync(path, `${content}
|
||||
function ${project}${file}Spread(...b: number[]) { }
|
||||
const ${project}${file}_ar = [20, 30];
|
||||
${project}${file}Spread(10, ...${project}${file}_ar);`);
|
||||
|
||||
replaceText(fs, `src/${project}/tsconfig.json`, `"strict": false,`, `"strict": false,
|
||||
"downlevelIteration": true,`);
|
||||
}
|
||||
|
||||
export function getTripleSlashRef(project: string) {
|
||||
return `/src/${project}/tripleRef.d.ts`;
|
||||
}
|
||||
|
||||
export function addTripleSlashRef(fs: vfs.FileSystem, project: string, file: string) {
|
||||
fs.writeFileSync(getTripleSlashRef(project), `declare class ${project}${file} { }`);
|
||||
prependText(fs, `src/${project}/${file}.ts`, `///<reference path="./tripleRef.d.ts"/>
|
||||
const ${file}Const = new ${project}${file}();
|
||||
`);
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as Utils from "../../_namespaces/Utils";
|
||||
import * as vfs from "../../_namespaces/vfs";
|
||||
import { appendText, compilerOptionsToConfigJson, libContent, loadProjectFromDisk, loadProjectFromFiles, noChangeOnlyRuns, noChangeRun, noChangeWithExportsDiscrepancyRun, prependText, replaceText, TestTscEdit, verifyTsc, verifyTscWithEdits } from "./helpers";
|
||||
|
||||
describe("unittests:: tsc:: incremental::", () => {
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "incremental",
|
||||
subScenario: "when passing filename for buildinfo on commandline",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/project/src/main.ts": "export const x = 10;",
|
||||
"/src/project/tsconfig.json": Utils.dedent`
|
||||
{
|
||||
@@ -20,13 +21,13 @@ describe("unittests:: tsc:: incremental::", () => {
|
||||
}`,
|
||||
}),
|
||||
commandLineArgs: ["--incremental", "--p", "src/project", "--tsBuildInfoFile", "src/project/.tsbuildinfo", "--explainFiles"],
|
||||
edits: ts.noChangeOnlyRuns
|
||||
edits: noChangeOnlyRuns
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "incremental",
|
||||
subScenario: "when passing rootDir from commandline",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/project/src/main.ts": "export const x = 10;",
|
||||
"/src/project/tsconfig.json": Utils.dedent`
|
||||
{
|
||||
@@ -37,31 +38,31 @@ describe("unittests:: tsc:: incremental::", () => {
|
||||
}`,
|
||||
}),
|
||||
commandLineArgs: ["--p", "src/project", "--rootDir", "src/project/src"],
|
||||
edits: ts.noChangeOnlyRuns
|
||||
edits: noChangeOnlyRuns
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "incremental",
|
||||
subScenario: "with only dts files",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/project/src/main.d.ts": "export const x = 10;",
|
||||
"/src/project/src/another.d.ts": "export const y = 10;",
|
||||
"/src/project/tsconfig.json": "{}",
|
||||
}),
|
||||
commandLineArgs: ["--incremental", "--p", "src/project"],
|
||||
edits: [
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
{
|
||||
subScenario: "incremental-declaration-doesnt-change",
|
||||
modifyFs: fs => ts.appendText(fs, "/src/project/src/main.d.ts", "export const xy = 100;")
|
||||
modifyFs: fs => appendText(fs, "/src/project/src/main.d.ts", "export const xy = 100;")
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "incremental",
|
||||
subScenario: "when passing rootDir is in the tsconfig",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/project/src/main.ts": "export const x = 10;",
|
||||
"/src/project/tsconfig.json": Utils.dedent`
|
||||
{
|
||||
@@ -73,13 +74,13 @@ describe("unittests:: tsc:: incremental::", () => {
|
||||
}`,
|
||||
}),
|
||||
commandLineArgs: ["--p", "src/project"],
|
||||
edits: ts.noChangeOnlyRuns
|
||||
edits: noChangeOnlyRuns
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "incremental",
|
||||
subScenario: "tsbuildinfo has error",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/project/main.ts": "export const x = 10;",
|
||||
"/src/project/tsconfig.json": "{}",
|
||||
"/src/project/tsconfig.tsbuildinfo": "Some random string",
|
||||
@@ -87,33 +88,33 @@ describe("unittests:: tsc:: incremental::", () => {
|
||||
commandLineArgs: ["--p", "src/project", "-i"],
|
||||
edits: [{
|
||||
subScenario: "tsbuildinfo written has error",
|
||||
modifyFs: fs => ts.prependText(fs, "/src/project/tsconfig.tsbuildinfo", "Some random string"),
|
||||
modifyFs: fs => prependText(fs, "/src/project/tsconfig.tsbuildinfo", "Some random string"),
|
||||
}]
|
||||
});
|
||||
|
||||
describe("with noEmitOnError", () => {
|
||||
let projFs: vfs.FileSystem;
|
||||
before(() => {
|
||||
projFs = ts.loadProjectFromDisk("tests/projects/noEmitOnError");
|
||||
projFs = loadProjectFromDisk("tests/projects/noEmitOnError");
|
||||
});
|
||||
after(() => {
|
||||
projFs = undefined!;
|
||||
});
|
||||
|
||||
function verifyNoEmitOnError(subScenario: string, fixModifyFs: ts.TestTscEdit["modifyFs"], modifyFs?: ts.TestTscEdit["modifyFs"]) {
|
||||
ts.verifyTscWithEdits({
|
||||
function verifyNoEmitOnError(subScenario: string, fixModifyFs: TestTscEdit["modifyFs"], modifyFs?: TestTscEdit["modifyFs"]) {
|
||||
verifyTscWithEdits({
|
||||
scenario: "incremental",
|
||||
subScenario,
|
||||
fs: () => projFs,
|
||||
commandLineArgs: ["--incremental", "-p", "src"],
|
||||
modifyFs,
|
||||
edits: [
|
||||
ts.noChangeWithExportsDiscrepancyRun,
|
||||
noChangeWithExportsDiscrepancyRun,
|
||||
{
|
||||
subScenario: "incremental-declaration-doesnt-change",
|
||||
modifyFs: fixModifyFs
|
||||
},
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
],
|
||||
baselinePrograms: true
|
||||
});
|
||||
@@ -142,25 +143,25 @@ const a: string = 10;`, "utf-8"),
|
||||
|
||||
function verifyNoEmitChanges(compilerOptions: ts.CompilerOptions) {
|
||||
const discrepancyExplanation = () => [
|
||||
...ts.noChangeWithExportsDiscrepancyRun.discrepancyExplanation!(),
|
||||
...noChangeWithExportsDiscrepancyRun.discrepancyExplanation!(),
|
||||
"Clean build will not have latestChangedDtsFile as there was no emit and emitSignatures as undefined for files",
|
||||
"Incremental will store the past latestChangedDtsFile and emitSignatures",
|
||||
];
|
||||
const discrepancyIfNoDtsEmit = ts.getEmitDeclarations(compilerOptions) ?
|
||||
undefined :
|
||||
ts.noChangeWithExportsDiscrepancyRun.discrepancyExplanation;
|
||||
const noChangeRunWithNoEmit: ts.TestTscEdit = {
|
||||
...ts.noChangeRun,
|
||||
noChangeWithExportsDiscrepancyRun.discrepancyExplanation;
|
||||
const noChangeRunWithNoEmit: TestTscEdit = {
|
||||
...noChangeRun,
|
||||
subScenario: "No Change run with noEmit",
|
||||
commandLineArgs: ["--p", "src/project", "--noEmit"],
|
||||
discrepancyExplanation: compilerOptions.composite ?
|
||||
discrepancyExplanation :
|
||||
!compilerOptions.declaration ?
|
||||
ts.noChangeWithExportsDiscrepancyRun.discrepancyExplanation :
|
||||
noChangeWithExportsDiscrepancyRun.discrepancyExplanation :
|
||||
undefined,
|
||||
};
|
||||
const noChangeRunWithEmit: ts.TestTscEdit = {
|
||||
...ts.noChangeRun,
|
||||
const noChangeRunWithEmit: TestTscEdit = {
|
||||
...noChangeRun,
|
||||
subScenario: "No Change run with emit",
|
||||
commandLineArgs: ["--p", "src/project"],
|
||||
discrepancyExplanation: discrepancyIfNoDtsEmit,
|
||||
@@ -172,7 +173,7 @@ const a: string = 10;`, "utf-8"),
|
||||
}
|
||||
}
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "incremental",
|
||||
subScenario: `noEmit changes${optionsString}`,
|
||||
commandLineArgs: ["--p", "src/project"],
|
||||
@@ -183,16 +184,16 @@ const a: string = 10;`, "utf-8"),
|
||||
{
|
||||
subScenario: "Introduce error but still noEmit",
|
||||
commandLineArgs: ["--p", "src/project", "--noEmit"],
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/project/src/class.ts", "prop", "prop1"),
|
||||
modifyFs: fs => replaceText(fs, "/src/project/src/class.ts", "prop", "prop1"),
|
||||
discrepancyExplanation: compilerOptions.composite ?
|
||||
discrepancyExplanation :
|
||||
compilerOptions.declaration ?
|
||||
ts.noChangeWithExportsDiscrepancyRun.discrepancyExplanation :
|
||||
noChangeWithExportsDiscrepancyRun.discrepancyExplanation :
|
||||
undefined,
|
||||
},
|
||||
{
|
||||
subScenario: "Fix error and emit",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/project/src/class.ts", "prop1", "prop"),
|
||||
modifyFs: fs => replaceText(fs, "/src/project/src/class.ts", "prop1", "prop"),
|
||||
discrepancyExplanation: discrepancyIfNoDtsEmit,
|
||||
},
|
||||
noChangeRunWithEmit,
|
||||
@@ -201,7 +202,7 @@ const a: string = 10;`, "utf-8"),
|
||||
noChangeRunWithEmit,
|
||||
{
|
||||
subScenario: "Introduce error and emit",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/project/src/class.ts", "prop", "prop1"),
|
||||
modifyFs: fs => replaceText(fs, "/src/project/src/class.ts", "prop", "prop1"),
|
||||
discrepancyExplanation: discrepancyIfNoDtsEmit,
|
||||
},
|
||||
noChangeRunWithEmit,
|
||||
@@ -211,10 +212,10 @@ const a: string = 10;`, "utf-8"),
|
||||
{
|
||||
subScenario: "Fix error and no emit",
|
||||
commandLineArgs: ["--p", "src/project", "--noEmit"],
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/project/src/class.ts", "prop1", "prop"),
|
||||
modifyFs: fs => replaceText(fs, "/src/project/src/class.ts", "prop1", "prop"),
|
||||
discrepancyExplanation: compilerOptions.composite ?
|
||||
discrepancyExplanation :
|
||||
ts.noChangeWithExportsDiscrepancyRun.discrepancyExplanation,
|
||||
noChangeWithExportsDiscrepancyRun.discrepancyExplanation,
|
||||
},
|
||||
noChangeRunWithEmit,
|
||||
noChangeRunWithNoEmit,
|
||||
@@ -223,7 +224,7 @@ const a: string = 10;`, "utf-8"),
|
||||
],
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "incremental",
|
||||
subScenario: `noEmit changes with initial noEmit${optionsString}`,
|
||||
commandLineArgs: ["--p", "src/project", "--noEmit"],
|
||||
@@ -233,21 +234,21 @@ const a: string = 10;`, "utf-8"),
|
||||
{
|
||||
subScenario: "Introduce error with emit",
|
||||
commandLineArgs: ["--p", "src/project"],
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/project/src/class.ts", "prop", "prop1"),
|
||||
modifyFs: fs => replaceText(fs, "/src/project/src/class.ts", "prop", "prop1"),
|
||||
},
|
||||
{
|
||||
subScenario: "Fix error and no emit",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/project/src/class.ts", "prop1", "prop"),
|
||||
modifyFs: fs => replaceText(fs, "/src/project/src/class.ts", "prop1", "prop"),
|
||||
discrepancyExplanation: compilerOptions.composite ?
|
||||
discrepancyExplanation :
|
||||
ts.noChangeWithExportsDiscrepancyRun.discrepancyExplanation,
|
||||
noChangeWithExportsDiscrepancyRun.discrepancyExplanation,
|
||||
},
|
||||
noChangeRunWithEmit,
|
||||
],
|
||||
});
|
||||
|
||||
function fs() {
|
||||
return ts.loadProjectFromFiles({
|
||||
return loadProjectFromFiles({
|
||||
"/src/project/src/class.ts": Utils.dedent`
|
||||
export class classC {
|
||||
prop = 1;
|
||||
@@ -275,10 +276,10 @@ const a: string = 10;`, "utf-8"),
|
||||
}
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "incremental",
|
||||
subScenario: `when global file is added, the signatures are updated`,
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/project/src/main.ts": Utils.dedent`
|
||||
/// <reference path="./filePresent.ts"/>
|
||||
/// <reference path="./fileNotFound.ts"/>
|
||||
@@ -297,22 +298,22 @@ const a: string = 10;`, "utf-8"),
|
||||
}),
|
||||
commandLineArgs: ["--p", "src/project"],
|
||||
edits: [
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
{
|
||||
subScenario: "Modify main file",
|
||||
modifyFs: fs => ts.appendText(fs, `/src/project/src/main.ts`, `something();`),
|
||||
modifyFs: fs => appendText(fs, `/src/project/src/main.ts`, `something();`),
|
||||
},
|
||||
{
|
||||
subScenario: "Modify main file again",
|
||||
modifyFs: fs => ts.appendText(fs, `/src/project/src/main.ts`, `something();`),
|
||||
modifyFs: fs => appendText(fs, `/src/project/src/main.ts`, `something();`),
|
||||
},
|
||||
{
|
||||
subScenario: "Add new file and update main file",
|
||||
modifyFs: fs => {
|
||||
fs.writeFileSync(`/src/project/src/newFile.ts`, "function foo() { return 20; }");
|
||||
ts.prependText(fs, `/src/project/src/main.ts`, `/// <reference path="./newFile.ts"/>
|
||||
prependText(fs, `/src/project/src/main.ts`, `/// <reference path="./newFile.ts"/>
|
||||
`);
|
||||
ts.appendText(fs, `/src/project/src/main.ts`, `foo();`);
|
||||
appendText(fs, `/src/project/src/main.ts`, `foo();`);
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -321,7 +322,7 @@ const a: string = 10;`, "utf-8"),
|
||||
},
|
||||
{
|
||||
subScenario: "Modify main file",
|
||||
modifyFs: fs => ts.appendText(fs, `/src/project/src/main.ts`, `something();`),
|
||||
modifyFs: fs => appendText(fs, `/src/project/src/main.ts`, `something();`),
|
||||
},
|
||||
],
|
||||
baselinePrograms: true,
|
||||
@@ -343,10 +344,10 @@ declare global {
|
||||
}`;
|
||||
}
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "react-jsx-emit-mode",
|
||||
subScenario: "with no backing types found doesn't crash",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/project/node_modules/react/jsx-runtime.js": "export {}", // js needs to be present so there's a resolution result
|
||||
"/src/project/node_modules/@types/react/index.d.ts": getJsxLibraryContent(), // doesn't contain a jsx-runtime definition
|
||||
"/src/project/src/index.tsx": `export const App = () => <div propA={true}></div>;`,
|
||||
@@ -355,10 +356,10 @@ declare global {
|
||||
commandLineArgs: ["--p", "src/project"]
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "react-jsx-emit-mode",
|
||||
subScenario: "with no backing types found doesn't crash under --strict",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/project/node_modules/react/jsx-runtime.js": "export {}", // js needs to be present so there's a resolution result
|
||||
"/src/project/node_modules/@types/react/index.d.ts": getJsxLibraryContent(), // doesn't contain a jsx-runtime definition
|
||||
"/src/project/src/index.tsx": `export const App = () => <div propA={true}></div>;`,
|
||||
@@ -368,11 +369,11 @@ declare global {
|
||||
});
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "incremental",
|
||||
subScenario: "when new file is added to the referenced project",
|
||||
commandLineArgs: ["-i", "-p", `src/projects/project2`],
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/projects/project1/tsconfig.json": JSON.stringify({
|
||||
compilerOptions: {
|
||||
module: "none",
|
||||
@@ -428,11 +429,11 @@ declare global {
|
||||
]
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "incremental",
|
||||
subScenario: "when project has strict true",
|
||||
commandLineArgs: ["-noEmit", "-p", `src/project`],
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/project/tsconfig.json": JSON.stringify({
|
||||
compilerOptions: {
|
||||
incremental: true,
|
||||
@@ -441,15 +442,15 @@ declare global {
|
||||
}),
|
||||
"/src/project/class1.ts": `export class class1 {}`,
|
||||
}),
|
||||
edits: ts.noChangeOnlyRuns,
|
||||
edits: noChangeOnlyRuns,
|
||||
baselinePrograms: true
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "incremental",
|
||||
subScenario: "serializing error chains",
|
||||
commandLineArgs: ["-p", `src/project`],
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/project/tsconfig.json": JSON.stringify({
|
||||
compilerOptions: {
|
||||
incremental: true,
|
||||
@@ -473,13 +474,13 @@ declare global {
|
||||
<div />
|
||||
</Component>)`
|
||||
}, `\ninterface ReadonlyArray<T> { readonly length: number }`),
|
||||
edits: ts.noChangeOnlyRuns,
|
||||
edits: noChangeOnlyRuns,
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "incremental",
|
||||
subScenario: "ts file with no-default-lib that augments the global scope",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/project/src/main.ts": Utils.dedent`
|
||||
/// <reference no-default-lib="true"/>
|
||||
/// <reference lib="esnext" />
|
||||
@@ -503,15 +504,15 @@ declare global {
|
||||
}),
|
||||
commandLineArgs: ["--p", "src/project", "--rootDir", "src/project/src"],
|
||||
modifyFs: (fs) => {
|
||||
fs.writeFileSync("/lib/lib.esnext.d.ts", ts.libContent);
|
||||
fs.writeFileSync("/lib/lib.esnext.d.ts", libContent);
|
||||
}
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "incremental",
|
||||
subScenario: "change to type that gets used as global through export in another file",
|
||||
commandLineArgs: ["-p", `src/project`],
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/project/tsconfig.json": JSON.stringify({ compilerOptions: { composite: true }, }),
|
||||
"/src/project/class1.ts": `const a: MagicNumber = 1;
|
||||
console.log(a);`,
|
||||
@@ -524,11 +525,11 @@ console.log(a);`,
|
||||
}],
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "incremental",
|
||||
subScenario: "change to type that gets used as global through export in another file through indirect import",
|
||||
commandLineArgs: ["-p", `src/project`],
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/project/tsconfig.json": JSON.stringify({ compilerOptions: { composite: true }, }),
|
||||
"/src/project/class1.ts": `const a: MagicNumber = 1;
|
||||
console.log(a);`,
|
||||
@@ -543,11 +544,11 @@ console.log(a);`,
|
||||
});
|
||||
|
||||
function verifyModifierChange(declaration: boolean) {
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "incremental",
|
||||
subScenario: `change to modifier of class expression field${declaration ? " with declaration emit enabled" : ""}`,
|
||||
commandLineArgs: ["-p", "src/project", "--incremental"],
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/project/tsconfig.json": JSON.stringify({ compilerOptions: { declaration } }),
|
||||
"/src/project/main.ts": Utils.dedent`
|
||||
import MessageablePerson from './MessageablePerson.js';
|
||||
@@ -564,18 +565,18 @@ console.log(a);`,
|
||||
type MessageablePerson = InstanceType<ReturnType<typeof wrapper>>;
|
||||
export default MessageablePerson;`,
|
||||
}),
|
||||
modifyFs: fs => ts.appendText(fs, "/lib/lib.d.ts", Utils.dedent`
|
||||
modifyFs: fs => appendText(fs, "/lib/lib.d.ts", Utils.dedent`
|
||||
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
|
||||
type InstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any;`
|
||||
),
|
||||
edits: [
|
||||
{
|
||||
subScenario: "modify public to protected",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/project/MessageablePerson.ts", "public", "protected"),
|
||||
modifyFs: fs => replaceText(fs, "/src/project/MessageablePerson.ts", "public", "protected"),
|
||||
},
|
||||
{
|
||||
subScenario: "modify protected to public",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/project/MessageablePerson.ts", "protected", "public"),
|
||||
modifyFs: fs => replaceText(fs, "/src/project/MessageablePerson.ts", "protected", "public"),
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -583,10 +584,10 @@ console.log(a);`,
|
||||
verifyModifierChange(/*declaration*/ false);
|
||||
verifyModifierChange(/*declaration*/ true);
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "incremental",
|
||||
subScenario: `when declarationMap changes`,
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/project/tsconfig.json": JSON.stringify({
|
||||
compilerOptions: {
|
||||
noEmitOnError: true,
|
||||
@@ -601,7 +602,7 @@ console.log(a);`,
|
||||
edits: [
|
||||
{
|
||||
subScenario: "error and enable declarationMap",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/project/a.ts", "x", "x: 20"),
|
||||
modifyFs: fs => replaceText(fs, "/src/project/a.ts", "x", "x: 20"),
|
||||
commandLineArgs: ["--p", "/src/project", "--declarationMap"],
|
||||
discrepancyExplanation: () => [
|
||||
`Clean build does not emit any file so will have emitSignatures with all files since they are not emitted`,
|
||||
@@ -611,16 +612,16 @@ console.log(a);`,
|
||||
},
|
||||
{
|
||||
subScenario: "fix error declarationMap",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/project/a.ts", "x: 20", "x"),
|
||||
modifyFs: fs => replaceText(fs, "/src/project/a.ts", "x: 20", "x"),
|
||||
commandLineArgs: ["--p", "/src/project", "--declarationMap"],
|
||||
},
|
||||
]
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "incremental",
|
||||
subScenario: `when declarationMap changes with outFile`,
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/project/tsconfig.json": JSON.stringify({
|
||||
compilerOptions: {
|
||||
noEmitOnError: true,
|
||||
@@ -636,29 +637,29 @@ console.log(a);`,
|
||||
edits: [
|
||||
{
|
||||
subScenario: "error and enable declarationMap",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/project/a.ts", "x", "x: 20"),
|
||||
modifyFs: fs => replaceText(fs, "/src/project/a.ts", "x", "x: 20"),
|
||||
commandLineArgs: ["--p", "/src/project", "--declarationMap"],
|
||||
},
|
||||
{
|
||||
subScenario: "fix error declarationMap",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/project/a.ts", "x: 20", "x"),
|
||||
modifyFs: fs => replaceText(fs, "/src/project/a.ts", "x: 20", "x"),
|
||||
commandLineArgs: ["--p", "/src/project", "--declarationMap"],
|
||||
},
|
||||
]
|
||||
});
|
||||
|
||||
describe("different options::", () => {
|
||||
function withOptionChange(subScenario: string, ...options: readonly string[]): ts.TestTscEdit {
|
||||
function withOptionChange(subScenario: string, ...options: readonly string[]): TestTscEdit {
|
||||
return {
|
||||
subScenario,
|
||||
modifyFs: ts.noop,
|
||||
commandLineArgs: ["--p", "/src/project", ...options],
|
||||
};
|
||||
}
|
||||
function noChangeWithSubscenario(subScenario: string): ts.TestTscEdit {
|
||||
return { ...ts.noChangeRun, subScenario };
|
||||
function noChangeWithSubscenario(subScenario: string): TestTscEdit {
|
||||
return { ...noChangeRun, subScenario };
|
||||
}
|
||||
function withOptionChangeAndDiscrepancyExplanation(subScenario: string, option: string): ts.TestTscEdit {
|
||||
function withOptionChangeAndDiscrepancyExplanation(subScenario: string, option: string): TestTscEdit {
|
||||
return {
|
||||
...withOptionChange(subScenario, option),
|
||||
discrepancyExplanation: () => [
|
||||
@@ -667,7 +668,7 @@ console.log(a);`,
|
||||
]
|
||||
};
|
||||
}
|
||||
function withEmitDeclarationOnlyChangeAndDiscrepancyExplanation(subScenario: string): ts.TestTscEdit {
|
||||
function withEmitDeclarationOnlyChangeAndDiscrepancyExplanation(subScenario: string): TestTscEdit {
|
||||
const edit = withOptionChangeAndDiscrepancyExplanation(subScenario, "--emitDeclarationOnly");
|
||||
const discrepancyExplanation = edit.discrepancyExplanation!;
|
||||
edit.discrepancyExplanation = () => [
|
||||
@@ -677,22 +678,22 @@ console.log(a);`,
|
||||
];
|
||||
return edit;
|
||||
}
|
||||
function withOptionChangeAndExportExplanation(subScenario: string, ...options: readonly string[]): ts.TestTscEdit {
|
||||
function withOptionChangeAndExportExplanation(subScenario: string, ...options: readonly string[]): TestTscEdit {
|
||||
return {
|
||||
...withOptionChange(subScenario, ...options),
|
||||
discrepancyExplanation: ts.noChangeWithExportsDiscrepancyRun.discrepancyExplanation,
|
||||
discrepancyExplanation: noChangeWithExportsDiscrepancyRun.discrepancyExplanation,
|
||||
};
|
||||
}
|
||||
function nochangeWithIncrementalDeclarationFromBeforeExplaination(): ts.TestTscEdit {
|
||||
function nochangeWithIncrementalDeclarationFromBeforeExplaination(): TestTscEdit {
|
||||
return {
|
||||
...ts.noChangeRun,
|
||||
...noChangeRun,
|
||||
discrepancyExplanation: () => [
|
||||
`Clean build tsbuildinfo will have compilerOptions {}`,
|
||||
`Incremental build will detect that it doesnt need to rebuild so tsbuild info is from before which has option declaration and declarationMap`,
|
||||
],
|
||||
};
|
||||
}
|
||||
function nochangeWithIncrementalOutDeclarationFromBeforeExplaination(): ts.TestTscEdit {
|
||||
function nochangeWithIncrementalOutDeclarationFromBeforeExplaination(): TestTscEdit {
|
||||
const edit = nochangeWithIncrementalDeclarationFromBeforeExplaination();
|
||||
const discrepancyExplanation = edit.discrepancyExplanation!;
|
||||
edit.discrepancyExplanation = () => [
|
||||
@@ -702,22 +703,22 @@ console.log(a);`,
|
||||
];
|
||||
return edit;
|
||||
}
|
||||
function localChange(): ts.TestTscEdit {
|
||||
function localChange(): TestTscEdit {
|
||||
return {
|
||||
subScenario: "local change",
|
||||
modifyFs: fs => ts.replaceText(fs, "/src/project/a.ts", "Local = 1", "Local = 10"),
|
||||
modifyFs: fs => replaceText(fs, "/src/project/a.ts", "Local = 1", "Local = 10"),
|
||||
};
|
||||
}
|
||||
function fs(options: ts.CompilerOptions) {
|
||||
return ts.loadProjectFromFiles({
|
||||
"/src/project/tsconfig.json": JSON.stringify({ compilerOptions: ts.compilerOptionsToConfigJson(options) }),
|
||||
return loadProjectFromFiles({
|
||||
"/src/project/tsconfig.json": JSON.stringify({ compilerOptions: compilerOptionsToConfigJson(options) }),
|
||||
"/src/project/a.ts": `export const a = 10;const aLocal = 10;`,
|
||||
"/src/project/b.ts": `export const b = 10;const bLocal = 10;`,
|
||||
"/src/project/c.ts": `import { a } from "./a";export const c = a;`,
|
||||
"/src/project/d.ts": `import { b } from "./b";export const d = b;`,
|
||||
});
|
||||
}
|
||||
function enableDeclarationMap(): ts.TestTscEdit {
|
||||
function enableDeclarationMap(): TestTscEdit {
|
||||
return {
|
||||
subScenario: "declarationMap enabling",
|
||||
modifyFs: fs => {
|
||||
@@ -727,7 +728,7 @@ console.log(a);`,
|
||||
},
|
||||
};
|
||||
}
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "incremental",
|
||||
subScenario: "different options",
|
||||
fs: () => fs({ composite: true }),
|
||||
@@ -736,11 +737,11 @@ console.log(a);`,
|
||||
withOptionChange("with sourceMap", "--sourceMap"),
|
||||
noChangeWithSubscenario("should re-emit only js so they dont contain sourcemap"),
|
||||
withOptionChangeAndDiscrepancyExplanation("with declaration should not emit anything", "--declaration"),
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
withOptionChange("with declaration and declarationMap", "--declaration", "--declarationMap"),
|
||||
noChangeWithSubscenario("should re-emit only dts so they dont contain sourcemap"),
|
||||
withOptionChangeAndDiscrepancyExplanation("with emitDeclarationOnly should not emit anything", "--emitDeclarationOnly"),
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
localChange(),
|
||||
withOptionChangeAndDiscrepancyExplanation("with declaration should not emit anything", "--declaration"),
|
||||
withOptionChange("with inlineSourceMap", "--inlineSourceMap"),
|
||||
@@ -750,7 +751,7 @@ console.log(a);`,
|
||||
],
|
||||
baselinePrograms: true,
|
||||
});
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "incremental",
|
||||
subScenario: "different options with outFile",
|
||||
fs: () => fs({ composite: true, outFile: "../outFile.js", module: ts.ModuleKind.AMD }),
|
||||
@@ -759,11 +760,11 @@ console.log(a);`,
|
||||
withOptionChange("with sourceMap", "--sourceMap"),
|
||||
noChangeWithSubscenario("should re-emit only js so they dont contain sourcemap"),
|
||||
withOptionChangeAndDiscrepancyExplanation("with declaration should not emit anything", "--declaration"),
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
withOptionChange("with declaration and declarationMap", "--declaration", "--declarationMap"),
|
||||
noChangeWithSubscenario("should re-emit only dts so they dont contain sourcemap"),
|
||||
withEmitDeclarationOnlyChangeAndDiscrepancyExplanation("with emitDeclarationOnly should not emit anything"),
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
localChange(),
|
||||
withOptionChangeAndDiscrepancyExplanation("with declaration should not emit anything", "--declaration"),
|
||||
withOptionChange("with inlineSourceMap", "--inlineSourceMap"),
|
||||
@@ -773,7 +774,7 @@ console.log(a);`,
|
||||
],
|
||||
baselinePrograms: true,
|
||||
});
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "incremental",
|
||||
subScenario: "different options with incremental",
|
||||
fs: () => fs({ incremental: true }),
|
||||
@@ -795,7 +796,7 @@ console.log(a);`,
|
||||
],
|
||||
baselinePrograms: true,
|
||||
});
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "incremental",
|
||||
subScenario: "different options with incremental with outFile",
|
||||
fs: () => fs({ incremental: true, outFile: "../outFile.js", module: ts.ModuleKind.AMD }),
|
||||
|
||||
@@ -1,43 +1,43 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as Utils from "../../_namespaces/Utils";
|
||||
import { loadProjectFromFiles, noChangeRun, verifyTsc, verifyTscWithEdits } from "./helpers";
|
||||
|
||||
describe("unittests:: tsc:: listFilesOnly::", () => {
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "listFilesOnly",
|
||||
subScenario: "combined with watch",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/test.ts": Utils.dedent`
|
||||
export const x = 1;`,
|
||||
}),
|
||||
commandLineArgs: ["/src/test.ts", "--watch", "--listFilesOnly"]
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "listFilesOnly",
|
||||
subScenario: "loose file",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/test.ts": Utils.dedent`
|
||||
export const x = 1;`,
|
||||
}),
|
||||
commandLineArgs: ["/src/test.ts", "--listFilesOnly"]
|
||||
});
|
||||
|
||||
ts.verifyTscWithEdits({
|
||||
verifyTscWithEdits({
|
||||
scenario: "listFilesOnly",
|
||||
subScenario: "combined with incremental",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/test.ts": `export const x = 1;`,
|
||||
"/src/tsconfig.json": "{}"
|
||||
}),
|
||||
commandLineArgs: ["-p", "/src", "--incremental", "--listFilesOnly"],
|
||||
edits: [
|
||||
{
|
||||
...ts.noChangeRun,
|
||||
...noChangeRun,
|
||||
commandLineArgs: ["-p", "/src", "--incremental"],
|
||||
},
|
||||
ts.noChangeRun,
|
||||
noChangeRun,
|
||||
{
|
||||
...ts.noChangeRun,
|
||||
...noChangeRun,
|
||||
commandLineArgs: ["-p", "/src", "--incremental"],
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { loadProjectFromFiles, verifyTsc } from "./helpers";
|
||||
|
||||
describe("unittests:: tsc:: projectReferences::", () => {
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "projectReferences",
|
||||
subScenario: "when project contains invalid project reference",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/project/src/main.ts": "export const x = 10;",
|
||||
"/src/project/tsconfig.json": JSON.stringify({
|
||||
compilerOptions: {
|
||||
@@ -19,10 +19,10 @@ describe("unittests:: tsc:: projectReferences::", () => {
|
||||
commandLineArgs: ["--p", "src/project"],
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "projectReferences",
|
||||
subScenario: "when project references composite project with noEmit",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/utils/index.ts": "export const x = 10;",
|
||||
"/src/utils/tsconfig.json": JSON.stringify({
|
||||
compilerOptions: {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { loadProjectFromFiles, verifyTsc } from "./helpers";
|
||||
|
||||
describe("unittests:: tsc:: redirect::", () => {
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "redirect",
|
||||
subScenario: "when redirecting ts file",
|
||||
fs: () => ts.loadProjectFromFiles({
|
||||
fs: () => loadProjectFromFiles({
|
||||
"/src/project/tsconfig.json": JSON.stringify({
|
||||
compilerOptions: {
|
||||
outDir: "out"
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { loadProjectFromFiles, verifyTsc } from "./helpers";
|
||||
|
||||
describe("unittests:: tsc:: runWithoutArgs::", () => {
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "runWithoutArgs",
|
||||
subScenario: "show help with ExitStatus.DiagnosticsPresent_OutputsSkipped",
|
||||
fs: () => ts.loadProjectFromFiles({}),
|
||||
fs: () => loadProjectFromFiles({}),
|
||||
commandLineArgs: [],
|
||||
environmentVariables: { TS_TEST_TERMINAL_WIDTH: "120" }
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "runWithoutArgs",
|
||||
subScenario: "show help with ExitStatus.DiagnosticsPresent_OutputsSkipped when host can't provide terminal width",
|
||||
fs: () => ts.loadProjectFromFiles({}),
|
||||
fs: () => loadProjectFromFiles({}),
|
||||
commandLineArgs: [],
|
||||
});
|
||||
|
||||
ts.verifyTsc({
|
||||
verifyTsc({
|
||||
scenario: "runWithoutArgs",
|
||||
subScenario: "does not add color when NO_COLOR is set",
|
||||
fs: () => ts.loadProjectFromFiles({}),
|
||||
fs: () => loadProjectFromFiles({}),
|
||||
commandLineArgs: [],
|
||||
environmentVariables: { NO_COLOR: "true" }
|
||||
});
|
||||
|
||||
@@ -1,24 +1,26 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { createWatchedSystem, File, libFile } from "../virtualFileSystemWithWatch";
|
||||
import { createBaseline, createWatchCompilerHostOfConfigFileForBaseline, runWatchBaseline, TscWatchCompileChange, verifyTscWatch } from "./helpers";
|
||||
|
||||
describe("unittests:: tsc-watch:: console clearing", () => {
|
||||
const scenario = "consoleClearing";
|
||||
const file: ts.tscWatch.File = {
|
||||
const file: File = {
|
||||
path: "/f.ts",
|
||||
content: ""
|
||||
};
|
||||
|
||||
const makeChangeToFile: ts.tscWatch.TscWatchCompileChange[] = [{
|
||||
const makeChangeToFile: TscWatchCompileChange[] = [{
|
||||
caption: "Comment added to file f",
|
||||
change: sys => sys.modifyFile(file.path, "//"),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks,
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
}];
|
||||
|
||||
function checkConsoleClearingUsingCommandLineOptions(subScenario: string, commandLineOptions?: string[]) {
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario,
|
||||
commandLineArgs: ["--w", file.path, ...commandLineOptions || ts.emptyArray],
|
||||
sys: () => ts.tscWatch.createWatchedSystem([file, ts.tscWatch.libFile]),
|
||||
sys: () => createWatchedSystem([file, libFile]),
|
||||
changes: makeChangeToFile,
|
||||
});
|
||||
}
|
||||
@@ -32,20 +34,20 @@ describe("unittests:: tsc-watch:: console clearing", () => {
|
||||
const compilerOptions: ts.CompilerOptions = {
|
||||
preserveWatchOutput: true
|
||||
};
|
||||
const configFile: ts.tscWatch.File = {
|
||||
const configFile: File = {
|
||||
path: "/tsconfig.json",
|
||||
content: JSON.stringify({ compilerOptions })
|
||||
};
|
||||
const files = [file, configFile, ts.tscWatch.libFile];
|
||||
const files = [file, configFile, libFile];
|
||||
it("using createWatchOfConfigFile ", () => {
|
||||
const baseline = ts.tscWatch.createBaseline(ts.tscWatch.createWatchedSystem(files));
|
||||
const watch = ts.createWatchProgram(ts.tscWatch.createWatchCompilerHostOfConfigFileForBaseline({
|
||||
const baseline = createBaseline(createWatchedSystem(files));
|
||||
const watch = ts.createWatchProgram(createWatchCompilerHostOfConfigFileForBaseline({
|
||||
system: baseline.sys,
|
||||
cb: baseline.cb,
|
||||
configFileName: configFile.path,
|
||||
}));
|
||||
// Initially console is cleared if --preserveOutput is not provided since the config file is yet to be parsed
|
||||
ts.tscWatch.runWatchBaseline({
|
||||
runWatchBaseline({
|
||||
scenario,
|
||||
subScenario: "when preserveWatchOutput is true in config file/createWatchOfConfigFile",
|
||||
commandLineArgs: ["--w", "-p", configFile.path],
|
||||
@@ -55,11 +57,11 @@ describe("unittests:: tsc-watch:: console clearing", () => {
|
||||
watchOrSolution: watch
|
||||
});
|
||||
});
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: "when preserveWatchOutput is true in config file/when createWatchProgram is invoked with configFileParseResult on WatchCompilerHostOfConfigFile",
|
||||
commandLineArgs: ["--w", "-p", configFile.path],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(files),
|
||||
sys: () => createWatchedSystem(files),
|
||||
changes: makeChangeToFile,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,28 +1,30 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { createWatchedSystem, File, libFile, TestServerHost } from "../virtualFileSystemWithWatch";
|
||||
import { TscWatchCompileChange, verifyTscWatch } from "./helpers";
|
||||
|
||||
const scenario = "emit";
|
||||
describe("unittests:: tsc-watch:: emit with outFile or out setting", () => {
|
||||
function verifyOutAndOutFileSetting(subScenario: string, out?: string, outFile?: string) {
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: `emit with outFile or out setting/${subScenario}`,
|
||||
commandLineArgs: ["--w", "-p", "/a/tsconfig.json"],
|
||||
sys: () => ts.tscWatch.createWatchedSystem({
|
||||
sys: () => createWatchedSystem({
|
||||
"/a/a.ts": "let x = 1",
|
||||
"/a/b.ts": "let y = 1",
|
||||
"/a/tsconfig.json": JSON.stringify({ compilerOptions: { out, outFile } }),
|
||||
[ts.tscWatch.libFile.path]: ts.tscWatch.libFile.content,
|
||||
[libFile.path]: libFile.content,
|
||||
}),
|
||||
changes: [
|
||||
{
|
||||
caption: "Make change in the file",
|
||||
change: sys => sys.writeFile("/a/a.ts", "let x = 11"),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks()
|
||||
},
|
||||
{
|
||||
caption: "Make change in the file again",
|
||||
change: sys => sys.writeFile("/a/a.ts", "let xy = 11"),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks()
|
||||
}
|
||||
]
|
||||
});
|
||||
@@ -32,28 +34,28 @@ describe("unittests:: tsc-watch:: emit with outFile or out setting", () => {
|
||||
verifyOutAndOutFileSetting("config has outFile", /*out*/ undefined, "/a/out.js");
|
||||
|
||||
function verifyFilesEmittedOnce(subScenario: string, useOutFile: boolean) {
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: `emit with outFile or out setting/${subScenario}`,
|
||||
commandLineArgs: ["--w", "-p", "/a/b/project/tsconfig.json"],
|
||||
sys: () => {
|
||||
const file1: ts.tscWatch.File = {
|
||||
const file1: File = {
|
||||
path: "/a/b/output/AnotherDependency/file1.d.ts",
|
||||
content: "declare namespace Common.SomeComponent.DynamicMenu { enum Z { Full = 0, Min = 1, Average = 2, } }"
|
||||
};
|
||||
const file2: ts.tscWatch.File = {
|
||||
const file2: File = {
|
||||
path: "/a/b/dependencies/file2.d.ts",
|
||||
content: "declare namespace Dependencies.SomeComponent { export class SomeClass { version: string; } }"
|
||||
};
|
||||
const file3: ts.tscWatch.File = {
|
||||
const file3: File = {
|
||||
path: "/a/b/project/src/main.ts",
|
||||
content: "namespace Main { export function fooBar() {} }"
|
||||
};
|
||||
const file4: ts.tscWatch.File = {
|
||||
const file4: File = {
|
||||
path: "/a/b/project/src/main2.ts",
|
||||
content: "namespace main.file4 { import DynamicMenu = Common.SomeComponent.DynamicMenu; export function foo(a: DynamicMenu.z) { } }"
|
||||
};
|
||||
const configFile: ts.tscWatch.File = {
|
||||
const configFile: File = {
|
||||
path: "/a/b/project/tsconfig.json",
|
||||
content: JSON.stringify({
|
||||
compilerOptions: useOutFile ?
|
||||
@@ -62,7 +64,7 @@ describe("unittests:: tsc-watch:: emit with outFile or out setting", () => {
|
||||
files: [file1.path, file2.path, file3.path, file4.path]
|
||||
})
|
||||
};
|
||||
return ts.tscWatch.createWatchedSystem([file1, file2, file3, file4, ts.tscWatch.libFile, configFile]);
|
||||
return createWatchedSystem([file1, file2, file3, file4, libFile, configFile]);
|
||||
},
|
||||
changes: ts.emptyArray
|
||||
});
|
||||
@@ -83,10 +85,10 @@ describe("unittests:: tsc-watch:: emit for configured projects", () => {
|
||||
/** custom config file options */
|
||||
configObj?: any;
|
||||
/** Additional files and folders to add */
|
||||
getAdditionalFileOrFolder?: () => ts.tscWatch.File[];
|
||||
getAdditionalFileOrFolder?: () => File[];
|
||||
/** initial list of files to emit if not the default list */
|
||||
firstReloadFileList?: string[];
|
||||
changes: ts.tscWatch.TscWatchCompileChange[]
|
||||
changes: TscWatchCompileChange[]
|
||||
}
|
||||
function verifyTscWatchEmit({
|
||||
subScenario,
|
||||
@@ -95,42 +97,42 @@ describe("unittests:: tsc-watch:: emit for configured projects", () => {
|
||||
firstReloadFileList,
|
||||
changes
|
||||
}: VerifyTscWatchEmit) {
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: `emit for configured projects/${subScenario}`,
|
||||
commandLineArgs: ["--w", "-p", configFilePath],
|
||||
sys: () => {
|
||||
const moduleFile1: ts.tscWatch.File = {
|
||||
const moduleFile1: File = {
|
||||
path: moduleFile1Path,
|
||||
content: "export function Foo() { };",
|
||||
};
|
||||
|
||||
const file1Consumer1: ts.tscWatch.File = {
|
||||
const file1Consumer1: File = {
|
||||
path: file1Consumer1Path,
|
||||
content: `import {Foo} from "./moduleFile1"; export var y = 10;`,
|
||||
};
|
||||
|
||||
const file1Consumer2: ts.tscWatch.File = {
|
||||
const file1Consumer2: File = {
|
||||
path: file1Consumer2Path,
|
||||
content: `import {Foo} from "./moduleFile1"; let z = 10;`,
|
||||
};
|
||||
|
||||
const moduleFile2: ts.tscWatch.File = {
|
||||
const moduleFile2: File = {
|
||||
path: moduleFile2Path,
|
||||
content: `export var Foo4 = 10;`,
|
||||
};
|
||||
|
||||
const globalFile3: ts.tscWatch.File = {
|
||||
const globalFile3: File = {
|
||||
path: globalFilePath,
|
||||
content: `interface GlobalFoo { age: number }`
|
||||
};
|
||||
const configFile: ts.tscWatch.File = {
|
||||
const configFile: File = {
|
||||
path: configFilePath,
|
||||
content: JSON.stringify(configObj || {})
|
||||
};
|
||||
const additionalFiles = getAdditionalFileOrFolder?.() || ts.emptyArray;
|
||||
const files = [moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, ts.tscWatch.libFile, ...additionalFiles];
|
||||
return ts.tscWatch.createWatchedSystem(firstReloadFileList ?
|
||||
const files = [moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, libFile, ...additionalFiles];
|
||||
return createWatchedSystem(firstReloadFileList ?
|
||||
ts.map(firstReloadFileList, fileName => ts.find(files, file => file.path === fileName)!) :
|
||||
files
|
||||
);
|
||||
@@ -139,13 +141,13 @@ describe("unittests:: tsc-watch:: emit for configured projects", () => {
|
||||
});
|
||||
}
|
||||
|
||||
function modifyModuleFile1Shape(sys: ts.tscWatch.WatchedSystem) {
|
||||
function modifyModuleFile1Shape(sys: TestServerHost) {
|
||||
sys.writeFile(moduleFile1Path, `export var T: number;export function Foo() { };`);
|
||||
}
|
||||
const changeModuleFile1Shape: ts.tscWatch.TscWatchCompileChange = {
|
||||
const changeModuleFile1Shape: TscWatchCompileChange = {
|
||||
caption: "Change the content of moduleFile1 to `export var T: number;export function Foo() { };`",
|
||||
change: modifyModuleFile1Shape,
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
};
|
||||
|
||||
verifyTscWatchEmit({
|
||||
@@ -155,7 +157,7 @@ describe("unittests:: tsc-watch:: emit for configured projects", () => {
|
||||
{
|
||||
caption: "Change the content of moduleFile1 to `export var T: number;export function Foo() { console.log('hi'); };`",
|
||||
change: sys => sys.writeFile(moduleFile1Path, `export var T: number;export function Foo() { console.log('hi'); };`),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
}
|
||||
]
|
||||
});
|
||||
@@ -166,18 +168,18 @@ describe("unittests:: tsc-watch:: emit for configured projects", () => {
|
||||
{
|
||||
caption: "Change file1Consumer1 content to `export let y = Foo();`",
|
||||
change: sys => sys.writeFile(file1Consumer1Path, `export let y = Foo();`),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
},
|
||||
changeModuleFile1Shape,
|
||||
{
|
||||
caption: "Add the import statements back to file1Consumer1",
|
||||
change: sys => sys.writeFile(file1Consumer1Path, `import {Foo} from "./moduleFile1";let y = Foo();`),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
},
|
||||
{
|
||||
caption: "Change the content of moduleFile1 to `export var T: number;export var T2: string;export function Foo() { };`",
|
||||
change: sys => sys.writeFile(moduleFile1Path, `export let y = Foo();`),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
},
|
||||
{
|
||||
caption: "Multiple file edits in one go",
|
||||
@@ -187,7 +189,7 @@ describe("unittests:: tsc-watch:: emit for configured projects", () => {
|
||||
sys.writeFile(file1Consumer1Path, `import {Foo} from "./moduleFile1";let y = Foo();`);
|
||||
modifyModuleFile1Shape(sys);
|
||||
},
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
}
|
||||
]
|
||||
});
|
||||
@@ -201,7 +203,7 @@ describe("unittests:: tsc-watch:: emit for configured projects", () => {
|
||||
modifyModuleFile1Shape(sys);
|
||||
sys.deleteFile(file1Consumer2Path);
|
||||
},
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
}
|
||||
]
|
||||
});
|
||||
@@ -215,7 +217,7 @@ describe("unittests:: tsc-watch:: emit for configured projects", () => {
|
||||
sys.writeFile("/a/b/file1Consumer3.ts", `import {Foo} from "./moduleFile1"; let y = Foo();`);
|
||||
modifyModuleFile1Shape(sys);
|
||||
},
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
}
|
||||
]
|
||||
});
|
||||
@@ -228,7 +230,7 @@ describe("unittests:: tsc-watch:: emit for configured projects", () => {
|
||||
{
|
||||
caption: "change file1 internal, and verify only file1 is affected",
|
||||
change: sys => sys.appendFile(moduleFile1Path, "var T1: number;"),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
}
|
||||
]
|
||||
});
|
||||
@@ -239,7 +241,7 @@ describe("unittests:: tsc-watch:: emit for configured projects", () => {
|
||||
{
|
||||
caption: "change shape of global file",
|
||||
change: sys => sys.appendFile(globalFilePath, "var T2: string;"),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
}
|
||||
]
|
||||
});
|
||||
@@ -270,7 +272,7 @@ describe("unittests:: tsc-watch:: emit for configured projects", () => {
|
||||
{
|
||||
caption: "change file1Consumer1",
|
||||
change: sys => sys.appendFile(file1Consumer1Path, "export var T: number;"),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
},
|
||||
changeModuleFile1Shape,
|
||||
{
|
||||
@@ -279,7 +281,7 @@ describe("unittests:: tsc-watch:: emit for configured projects", () => {
|
||||
sys.appendFile(file1Consumer1Path, "export var T2: number;");
|
||||
sys.writeFile(moduleFile1Path, `export var T2: number;export function Foo() { };`);
|
||||
},
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
}
|
||||
]
|
||||
});
|
||||
@@ -298,12 +300,12 @@ export var t1 = 10;`
|
||||
export var t2 = 10;`
|
||||
}
|
||||
],
|
||||
firstReloadFileList: [ts.tscWatch.libFile.path, "/a/b/file1.ts", "/a/b/file2.ts", configFilePath],
|
||||
firstReloadFileList: [libFile.path, "/a/b/file1.ts", "/a/b/file2.ts", configFilePath],
|
||||
changes: [
|
||||
{
|
||||
caption: "change file1",
|
||||
change: sys => sys.appendFile("/a/b/file1.ts", "export var t3 = 10;"),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
}
|
||||
]
|
||||
});
|
||||
@@ -315,12 +317,12 @@ export var t2 = 10;`
|
||||
content: `/// <reference path="./moduleFile1.ts" />
|
||||
export var x = Foo();`
|
||||
}],
|
||||
firstReloadFileList: [ts.tscWatch.libFile.path, "/a/b/referenceFile1.ts", moduleFile1Path, configFilePath],
|
||||
firstReloadFileList: [libFile.path, "/a/b/referenceFile1.ts", moduleFile1Path, configFilePath],
|
||||
changes: [
|
||||
{
|
||||
caption: "delete moduleFile1",
|
||||
change: sys => sys.deleteFile(moduleFile1Path),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
}
|
||||
]
|
||||
});
|
||||
@@ -332,17 +334,17 @@ export var x = Foo();`
|
||||
content: `/// <reference path="./moduleFile2.ts" />
|
||||
export var x = Foo();`
|
||||
}],
|
||||
firstReloadFileList: [ts.tscWatch.libFile.path, "/a/b/referenceFile1.ts", configFilePath],
|
||||
firstReloadFileList: [libFile.path, "/a/b/referenceFile1.ts", configFilePath],
|
||||
changes: [
|
||||
{
|
||||
caption: "edit refereceFile1",
|
||||
change: sys => sys.appendFile("/a/b/referenceFile1.ts", "export var yy = Foo();"),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
},
|
||||
{
|
||||
caption: "create moduleFile2",
|
||||
change: sys => sys.writeFile(moduleFile2Path, "export var Foo4 = 10;"),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
}
|
||||
]
|
||||
});
|
||||
@@ -350,17 +352,17 @@ export var x = Foo();`
|
||||
|
||||
describe("unittests:: tsc-watch:: emit file content", () => {
|
||||
function verifyNewLine(subScenario: string, newLine: string) {
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: `emit file content/${subScenario}`,
|
||||
commandLineArgs: ["--w", "/a/app.ts"],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
sys: () => createWatchedSystem(
|
||||
[
|
||||
{
|
||||
path: "/a/app.ts",
|
||||
content: ["var x = 1;", "var y = 2;"].join(newLine)
|
||||
},
|
||||
ts.tscWatch.libFile
|
||||
libFile
|
||||
],
|
||||
{ newLine }
|
||||
),
|
||||
@@ -368,7 +370,7 @@ describe("unittests:: tsc-watch:: emit file content", () => {
|
||||
{
|
||||
caption: "Append a line",
|
||||
change: sys => sys.appendFile("/a/app.ts", newLine + "var z = 3;"),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
}
|
||||
],
|
||||
});
|
||||
@@ -376,7 +378,7 @@ describe("unittests:: tsc-watch:: emit file content", () => {
|
||||
verifyNewLine("handles new lines lineFeed", "\n");
|
||||
verifyNewLine("handles new lines carriageReturn lineFeed", "\r\n");
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: "emit file content/should emit specified file",
|
||||
commandLineArgs: ["-w", "-p", "/a/b/tsconfig.json"],
|
||||
@@ -400,62 +402,62 @@ describe("unittests:: tsc-watch:: emit file content", () => {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: "{}"
|
||||
};
|
||||
return ts.tscWatch.createWatchedSystem([file1, file2, file3, configFile, ts.tscWatch.libFile]);
|
||||
return createWatchedSystem([file1, file2, file3, configFile, libFile]);
|
||||
},
|
||||
changes: [
|
||||
{
|
||||
caption: "Append content to f1",
|
||||
change: sys => sys.appendFile("/a/b/f1.ts", "export function foo2() { return 2; }"),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
},
|
||||
{
|
||||
caption: "Again Append content to f1",
|
||||
change: sys => sys.appendFile("/a/b/f1.ts", "export function fooN() { return 2; }"),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: "emit file content/elides const enums correctly in incremental compilation",
|
||||
commandLineArgs: ["-w", "/user/someone/projects/myproject/file3.ts"],
|
||||
sys: () => {
|
||||
const currentDirectory = "/user/someone/projects/myproject";
|
||||
const file1: ts.tscWatch.File = {
|
||||
const file1: File = {
|
||||
path: `${currentDirectory}/file1.ts`,
|
||||
content: "export const enum E1 { V = 1 }"
|
||||
};
|
||||
const file2: ts.tscWatch.File = {
|
||||
const file2: File = {
|
||||
path: `${currentDirectory}/file2.ts`,
|
||||
content: `import { E1 } from "./file1"; export const enum E2 { V = E1.V }`
|
||||
};
|
||||
const file3: ts.tscWatch.File = {
|
||||
const file3: File = {
|
||||
path: `${currentDirectory}/file3.ts`,
|
||||
content: `import { E2 } from "./file2"; const v: E2 = E2.V;`
|
||||
};
|
||||
return ts.tscWatch.createWatchedSystem([file1, file2, file3, ts.tscWatch.libFile]);
|
||||
return createWatchedSystem([file1, file2, file3, libFile]);
|
||||
},
|
||||
changes: [
|
||||
{
|
||||
caption: "Append content to file3",
|
||||
change: sys => sys.appendFile("/user/someone/projects/myproject/file3.ts", "function foo2() { return 2; }"),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: "emit file content/file is deleted and created as part of change",
|
||||
commandLineArgs: ["-w"],
|
||||
sys: () => {
|
||||
const projectLocation = "/home/username/project";
|
||||
const file: ts.tscWatch.File = {
|
||||
const file: File = {
|
||||
path: `${projectLocation}/app/file.ts`,
|
||||
content: "var a = 10;"
|
||||
};
|
||||
const configFile: ts.tscWatch.File = {
|
||||
const configFile: File = {
|
||||
path: `${projectLocation}/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
include: [
|
||||
@@ -463,26 +465,26 @@ describe("unittests:: tsc-watch:: emit file content", () => {
|
||||
]
|
||||
})
|
||||
};
|
||||
const files = [file, configFile, ts.tscWatch.libFile];
|
||||
return ts.tscWatch.createWatchedSystem(files, { currentDirectory: projectLocation, useCaseSensitiveFileNames: true });
|
||||
const files = [file, configFile, libFile];
|
||||
return createWatchedSystem(files, { currentDirectory: projectLocation, useCaseSensitiveFileNames: true });
|
||||
},
|
||||
changes: [
|
||||
{
|
||||
caption: "file is deleted and then created to modify content",
|
||||
change: sys => sys.appendFile("/home/username/project/app/file.ts", "\nvar b = 10;", { invokeFileDeleteCreateAsPartInsteadOfChange: true }),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
describe("unittests:: tsc-watch:: emit with when module emit is specified as node", () => {
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: "when module emit is specified as node/when instead of filechanged recursive directory watcher is invoked",
|
||||
commandLineArgs: ["--w", "--p", "/a/rootFolder/project/tsconfig.json"],
|
||||
sys: () => {
|
||||
const configFile: ts.tscWatch.File = {
|
||||
const configFile: File = {
|
||||
path: "/a/rootFolder/project/tsconfig.json",
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
@@ -495,15 +497,15 @@ describe("unittests:: tsc-watch:: emit with when module emit is specified as nod
|
||||
],
|
||||
})
|
||||
};
|
||||
const file1: ts.tscWatch.File = {
|
||||
const file1: File = {
|
||||
path: "/a/rootFolder/project/Scripts/TypeScript.ts",
|
||||
content: "var z = 10;"
|
||||
};
|
||||
const file2: ts.tscWatch.File = {
|
||||
const file2: File = {
|
||||
path: "/a/rootFolder/project/Scripts/Javascript.js",
|
||||
content: "var zz = 10;"
|
||||
};
|
||||
return ts.tscWatch.createWatchedSystem([configFile, file1, file2, ts.tscWatch.libFile]);
|
||||
return createWatchedSystem([configFile, file1, file2, libFile]);
|
||||
},
|
||||
changes: [
|
||||
{
|
||||
@@ -513,7 +515,7 @@ describe("unittests:: tsc-watch:: emit with when module emit is specified as nod
|
||||
"var zz30 = 100;",
|
||||
{ invokeDirectoryWatcherInsteadOfFileChanged: true },
|
||||
),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks,
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { createWatchedSystem, File, getTsBuildProjectFile, libFile } from "../virtualFileSystemWithWatch";
|
||||
import { libContent } from "../tsc/helpers";
|
||||
import { TscWatchCompileChange, verifyTscWatch } from "./helpers";
|
||||
|
||||
describe("unittests:: tsc-watch:: Emit times and Error updates in builder after program changes", () => {
|
||||
const config: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const config: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: `{}`
|
||||
};
|
||||
interface VerifyEmitAndErrorUpdates {
|
||||
subScenario: string
|
||||
files: () => ts.tscWatch.File[];
|
||||
files: () => File[];
|
||||
currentDirectory?: string;
|
||||
changes: ts.tscWatch.TscWatchCompileChange[];
|
||||
changes: TscWatchCompileChange[];
|
||||
}
|
||||
function verifyEmitAndErrorUpdates({
|
||||
subScenario,
|
||||
@@ -17,73 +19,73 @@ describe("unittests:: tsc-watch:: Emit times and Error updates in builder after
|
||||
currentDirectory,
|
||||
changes,
|
||||
}: VerifyEmitAndErrorUpdates) {
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "emitAndErrorUpdates",
|
||||
subScenario: `default/${subScenario}`,
|
||||
commandLineArgs: ["--w"],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
sys: () => createWatchedSystem(
|
||||
files(),
|
||||
{ currentDirectory: currentDirectory || ts.tscWatch.projectRoot }
|
||||
{ currentDirectory: currentDirectory || "/user/username/projects/myproject" }
|
||||
),
|
||||
changes,
|
||||
baselineIncremental: true
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "emitAndErrorUpdates",
|
||||
subScenario: `defaultAndD/${subScenario}`,
|
||||
commandLineArgs: ["--w", "--d"],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
sys: () => createWatchedSystem(
|
||||
files(),
|
||||
{ currentDirectory: currentDirectory || ts.tscWatch.projectRoot }
|
||||
{ currentDirectory: currentDirectory || "/user/username/projects/myproject" }
|
||||
),
|
||||
changes,
|
||||
baselineIncremental: true
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "emitAndErrorUpdates",
|
||||
subScenario: `isolatedModules/${subScenario}`,
|
||||
commandLineArgs: ["--w", "--isolatedModules"],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
sys: () => createWatchedSystem(
|
||||
files(),
|
||||
{ currentDirectory: currentDirectory || ts.tscWatch.projectRoot }
|
||||
{ currentDirectory: currentDirectory || "/user/username/projects/myproject" }
|
||||
),
|
||||
changes,
|
||||
baselineIncremental: true
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "emitAndErrorUpdates",
|
||||
subScenario: `isolatedModulesAndD/${subScenario}`,
|
||||
commandLineArgs: ["--w", "--isolatedModules", "--d"],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
sys: () => createWatchedSystem(
|
||||
files(),
|
||||
{ currentDirectory: currentDirectory || ts.tscWatch.projectRoot }
|
||||
{ currentDirectory: currentDirectory || "/user/username/projects/myproject" }
|
||||
),
|
||||
changes,
|
||||
baselineIncremental: true
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "emitAndErrorUpdates",
|
||||
subScenario: `assumeChangesOnlyAffectDirectDependencies/${subScenario}`,
|
||||
commandLineArgs: ["--w", "--assumeChangesOnlyAffectDirectDependencies"],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
sys: () => createWatchedSystem(
|
||||
files(),
|
||||
{ currentDirectory: currentDirectory || ts.tscWatch.projectRoot }
|
||||
{ currentDirectory: currentDirectory || "/user/username/projects/myproject" }
|
||||
),
|
||||
changes,
|
||||
baselineIncremental: true
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "emitAndErrorUpdates",
|
||||
subScenario: `assumeChangesOnlyAffectDirectDependenciesAndD/${subScenario}`,
|
||||
commandLineArgs: ["--w", "--assumeChangesOnlyAffectDirectDependencies", "--d"],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
sys: () => createWatchedSystem(
|
||||
files(),
|
||||
{ currentDirectory: currentDirectory || ts.tscWatch.projectRoot }
|
||||
{ currentDirectory: currentDirectory || "/user/username/projects/myproject" }
|
||||
),
|
||||
changes,
|
||||
baselineIncremental: true
|
||||
@@ -91,48 +93,48 @@ describe("unittests:: tsc-watch:: Emit times and Error updates in builder after
|
||||
}
|
||||
|
||||
describe("deep import changes", () => {
|
||||
const aFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/a.ts`,
|
||||
const aFile: File = {
|
||||
path: `/user/username/projects/myproject/a.ts`,
|
||||
content: `import {B} from './b';
|
||||
declare var console: any;
|
||||
let b = new B();
|
||||
console.log(b.c.d);`
|
||||
};
|
||||
|
||||
function verifyDeepImportChange(subScenario: string, bFile: ts.tscWatch.File, cFile: ts.tscWatch.File) {
|
||||
function verifyDeepImportChange(subScenario: string, bFile: File, cFile: File) {
|
||||
verifyEmitAndErrorUpdates({
|
||||
subScenario: `deepImportChanges/${subScenario}`,
|
||||
files: () => [aFile, bFile, cFile, config, ts.tscWatch.libFile],
|
||||
files: () => [aFile, bFile, cFile, config, libFile],
|
||||
changes: [
|
||||
{
|
||||
caption: "Rename property d to d2 of class C to initialize signatures",
|
||||
change: sys => sys.writeFile(cFile.path, cFile.content.replace("d", "d2")),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks,
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
},
|
||||
{
|
||||
caption: "Rename property d2 to d of class C to revert back to original text",
|
||||
change: sys => sys.writeFile(cFile.path, cFile.content.replace("d2", "d")),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks,
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
},
|
||||
{
|
||||
caption: "Rename property d to d2 of class C",
|
||||
change: sys => sys.writeFile(cFile.path, cFile.content.replace("d", "d2")),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks,
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
}
|
||||
],
|
||||
});
|
||||
}
|
||||
describe("updates errors when deep import file changes", () => {
|
||||
const bFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/b.ts`,
|
||||
const bFile: File = {
|
||||
path: `/user/username/projects/myproject/b.ts`,
|
||||
content: `import {C} from './c';
|
||||
export class B
|
||||
{
|
||||
c = new C();
|
||||
}`
|
||||
};
|
||||
const cFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/c.ts`,
|
||||
const cFile: File = {
|
||||
path: `/user/username/projects/myproject/c.ts`,
|
||||
content: `export class C
|
||||
{
|
||||
d = 1;
|
||||
@@ -145,16 +147,16 @@ export class B
|
||||
);
|
||||
});
|
||||
describe("updates errors when deep import through declaration file changes", () => {
|
||||
const bFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/b.d.ts`,
|
||||
const bFile: File = {
|
||||
path: `/user/username/projects/myproject/b.d.ts`,
|
||||
content: `import {C} from './c';
|
||||
export class B
|
||||
{
|
||||
c: C;
|
||||
}`
|
||||
};
|
||||
const cFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/c.d.ts`,
|
||||
const cFile: File = {
|
||||
path: `/user/username/projects/myproject/c.d.ts`,
|
||||
content: `export class C
|
||||
{
|
||||
d: number;
|
||||
@@ -169,8 +171,8 @@ export class B
|
||||
});
|
||||
|
||||
describe("updates errors in file not exporting a deep multilevel import that changes", () => {
|
||||
const aFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/a.ts`,
|
||||
const aFile: File = {
|
||||
path: `/user/username/projects/myproject/a.ts`,
|
||||
content: `export interface Point {
|
||||
name: string;
|
||||
c: Coords;
|
||||
@@ -180,14 +182,14 @@ export interface Coords {
|
||||
y: number;
|
||||
}`
|
||||
};
|
||||
const bFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/b.ts`,
|
||||
const bFile: File = {
|
||||
path: `/user/username/projects/myproject/b.ts`,
|
||||
content: `import { Point } from "./a";
|
||||
export interface PointWrapper extends Point {
|
||||
}`
|
||||
};
|
||||
const cFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/c.ts`,
|
||||
const cFile: File = {
|
||||
path: `/user/username/projects/myproject/c.ts`,
|
||||
content: `import { PointWrapper } from "./b";
|
||||
export function getPoint(): PointWrapper {
|
||||
return {
|
||||
@@ -199,47 +201,47 @@ export function getPoint(): PointWrapper {
|
||||
}
|
||||
};`
|
||||
};
|
||||
const dFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/d.ts`,
|
||||
const dFile: File = {
|
||||
path: `/user/username/projects/myproject/d.ts`,
|
||||
content: `import { getPoint } from "./c";
|
||||
getPoint().c.x;`
|
||||
};
|
||||
const eFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/e.ts`,
|
||||
const eFile: File = {
|
||||
path: `/user/username/projects/myproject/e.ts`,
|
||||
content: `import "./d";`
|
||||
};
|
||||
verifyEmitAndErrorUpdates({
|
||||
subScenario: "file not exporting a deep multilevel import that changes",
|
||||
files: () => [aFile, bFile, cFile, dFile, eFile, config, ts.tscWatch.libFile],
|
||||
files: () => [aFile, bFile, cFile, dFile, eFile, config, libFile],
|
||||
changes: [
|
||||
{
|
||||
caption: "Rename property x2 to x of interface Coords to initialize signatures",
|
||||
change: sys => sys.writeFile(aFile.path, aFile.content.replace("x2", "x")),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks,
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
},
|
||||
{
|
||||
caption: "Rename property x to x2 of interface Coords to revert back to original text",
|
||||
change: sys => sys.writeFile(aFile.path, aFile.content.replace("x: number", "x2: number")),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks,
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
},
|
||||
{
|
||||
caption: "Rename property x2 to x of interface Coords",
|
||||
change: sys => sys.writeFile(aFile.path, aFile.content.replace("x2", "x")),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks,
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
},
|
||||
]
|
||||
});
|
||||
});
|
||||
describe("updates errors when file transitively exported file changes", () => {
|
||||
const config: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const config: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
files: ["app.ts"],
|
||||
compilerOptions: { baseUrl: "." }
|
||||
})
|
||||
};
|
||||
const app: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/app.ts`,
|
||||
const app: File = {
|
||||
path: `/user/username/projects/myproject/app.ts`,
|
||||
content: `import { Data } from "lib2/public";
|
||||
export class App {
|
||||
public constructor() {
|
||||
@@ -247,12 +249,12 @@ export class App {
|
||||
}
|
||||
}`
|
||||
};
|
||||
const lib2Public: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/lib2/public.ts`,
|
||||
const lib2Public: File = {
|
||||
path: `/user/username/projects/myproject/lib2/public.ts`,
|
||||
content: `export * from "./data";`
|
||||
};
|
||||
const lib2Data: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/lib2/data.ts`,
|
||||
const lib2Data: File = {
|
||||
path: `/user/username/projects/myproject/lib2/data.ts`,
|
||||
content: `import { ITest } from "lib1/public";
|
||||
export class Data {
|
||||
public test() {
|
||||
@@ -263,40 +265,40 @@ export class Data {
|
||||
}
|
||||
}`
|
||||
};
|
||||
const lib1Public: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/lib1/public.ts`,
|
||||
const lib1Public: File = {
|
||||
path: `/user/username/projects/myproject/lib1/public.ts`,
|
||||
content: `export * from "./tools/public";`
|
||||
};
|
||||
const lib1ToolsPublic: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/lib1/tools/public.ts`,
|
||||
const lib1ToolsPublic: File = {
|
||||
path: `/user/username/projects/myproject/lib1/tools/public.ts`,
|
||||
content: `export * from "./tools.interface";`
|
||||
};
|
||||
const lib1ToolsInterface: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/lib1/tools/tools.interface.ts`,
|
||||
const lib1ToolsInterface: File = {
|
||||
path: `/user/username/projects/myproject/lib1/tools/tools.interface.ts`,
|
||||
content: `export interface ITest {
|
||||
title: string;
|
||||
}`
|
||||
};
|
||||
|
||||
function verifyTransitiveExports(subScenario: string, files: readonly ts.tscWatch.File[]) {
|
||||
function verifyTransitiveExports(subScenario: string, files: readonly File[]) {
|
||||
verifyEmitAndErrorUpdates({
|
||||
subScenario: `transitive exports/${subScenario}`,
|
||||
files: () => [lib1ToolsInterface, lib1ToolsPublic, app, lib2Public, lib1Public, ...files, config, ts.tscWatch.libFile],
|
||||
files: () => [lib1ToolsInterface, lib1ToolsPublic, app, lib2Public, lib1Public, ...files, config, libFile],
|
||||
changes: [
|
||||
{
|
||||
caption: "Rename property title to title2 of interface ITest to initialize signatures",
|
||||
change: sys => sys.writeFile(lib1ToolsInterface.path, lib1ToolsInterface.content.replace("title", "title2")),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks,
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
},
|
||||
{
|
||||
caption: "Rename property title2 to title of interface ITest to revert back to original text",
|
||||
change: sys => sys.writeFile(lib1ToolsInterface.path, lib1ToolsInterface.content.replace("title2", "title")),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks,
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
},
|
||||
{
|
||||
caption: "Rename property title to title2 of interface ITest",
|
||||
change: sys => sys.writeFile(lib1ToolsInterface.path, lib1ToolsInterface.content.replace("title", "title2")),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks,
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
}
|
||||
]
|
||||
});
|
||||
@@ -308,8 +310,8 @@ export class Data {
|
||||
);
|
||||
});
|
||||
describe("when there are circular import and exports", () => {
|
||||
const lib2Data: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/lib2/data.ts`,
|
||||
const lib2Data: File = {
|
||||
path: `/user/username/projects/myproject/lib2/data.ts`,
|
||||
content: `import { ITest } from "lib1/public"; import { Data2 } from "./data2";
|
||||
export class Data {
|
||||
public dat?: Data2; public test() {
|
||||
@@ -320,8 +322,8 @@ export class Data {
|
||||
}
|
||||
}`
|
||||
};
|
||||
const lib2Data2: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/lib2/data2.ts`,
|
||||
const lib2Data2: File = {
|
||||
path: `/user/username/projects/myproject/lib2/data2.ts`,
|
||||
content: `import { Data } from "./data";
|
||||
export class Data2 {
|
||||
public dat?: Data;
|
||||
@@ -335,25 +337,25 @@ export class Data2 {
|
||||
});
|
||||
|
||||
describe("with noEmitOnError", () => {
|
||||
function change(caption: string, content: string): ts.tscWatch.TscWatchCompileChange {
|
||||
function change(caption: string, content: string): TscWatchCompileChange {
|
||||
return {
|
||||
caption,
|
||||
change: sys => sys.writeFile(`${ts.TestFSWithWatch.tsbuildProjectsLocation}/noEmitOnError/src/main.ts`, content),
|
||||
change: sys => sys.writeFile(`/user/username/projects/noEmitOnError/src/main.ts`, content),
|
||||
// build project
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1)
|
||||
};
|
||||
}
|
||||
const noChange: ts.tscWatch.TscWatchCompileChange = {
|
||||
const noChange: TscWatchCompileChange = {
|
||||
caption: "No change",
|
||||
change: sys => sys.writeFile(`${ts.TestFSWithWatch.tsbuildProjectsLocation}/noEmitOnError/src/main.ts`, sys.readFile(`${ts.TestFSWithWatch.tsbuildProjectsLocation}/noEmitOnError/src/main.ts`)!),
|
||||
change: sys => sys.writeFile(`/user/username/projects/noEmitOnError/src/main.ts`, sys.readFile(`/user/username/projects/noEmitOnError/src/main.ts`)!),
|
||||
// build project
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
};
|
||||
verifyEmitAndErrorUpdates({
|
||||
subScenario: "with noEmitOnError",
|
||||
currentDirectory: `${ts.TestFSWithWatch.tsbuildProjectsLocation}/noEmitOnError`,
|
||||
currentDirectory: `/user/username/projects/noEmitOnError`,
|
||||
files: () => ["shared/types/db.ts", "src/main.ts", "src/other.ts", "tsconfig.json"]
|
||||
.map(f => ts.TestFSWithWatch.getTsBuildProjectFile("noEmitOnError", f)).concat({ path: ts.tscWatch.libFile.path, content: ts.libContent }),
|
||||
.map(f => getTsBuildProjectFile("noEmitOnError", f)).concat({ path: libFile.path, content: libContent }),
|
||||
changes: [
|
||||
noChange,
|
||||
change("Fix Syntax error", `import { A } from "../shared/types/db";
|
||||
|
||||
@@ -1,28 +1,30 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as Utils from "../../_namespaces/Utils";
|
||||
import { createWatchedSystem, File, libFile, SymLink } from "../virtualFileSystemWithWatch";
|
||||
import { TscWatchCompileChange, verifyTscWatch } from "./helpers";
|
||||
|
||||
describe("unittests:: tsc-watch:: forceConsistentCasingInFileNames", () => {
|
||||
const loggerFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/logger.ts`,
|
||||
const loggerFile: File = {
|
||||
path: `/user/username/projects/myproject/logger.ts`,
|
||||
content: `export class logger { }`
|
||||
};
|
||||
const anotherFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/another.ts`,
|
||||
const anotherFile: File = {
|
||||
path: `/user/username/projects/myproject/another.ts`,
|
||||
content: `import { logger } from "./logger"; new logger();`
|
||||
};
|
||||
const tsconfig: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const tsconfig: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { forceConsistentCasingInFileNames: true }
|
||||
})
|
||||
};
|
||||
|
||||
function verifyConsistentFileNames({ subScenario, changes }: { subScenario: string; changes: ts.tscWatch.TscWatchCompileChange[]; }) {
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
function verifyConsistentFileNames({ subScenario, changes }: { subScenario: string; changes: TscWatchCompileChange[]; }) {
|
||||
verifyTscWatch({
|
||||
scenario: "forceConsistentCasingInFileNames",
|
||||
subScenario,
|
||||
commandLineArgs: ["--w", "--p", tsconfig.path],
|
||||
sys: () => ts.tscWatch.createWatchedSystem([loggerFile, anotherFile, tsconfig, ts.tscWatch.libFile]),
|
||||
sys: () => createWatchedSystem([loggerFile, anotherFile, tsconfig, libFile]),
|
||||
changes
|
||||
});
|
||||
}
|
||||
@@ -33,7 +35,7 @@ describe("unittests:: tsc-watch:: forceConsistentCasingInFileNames", () => {
|
||||
{
|
||||
caption: "Change module name from logger to Logger",
|
||||
change: sys => sys.writeFile(anotherFile.path, anotherFile.content.replace("./logger", "./Logger")),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks,
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
}
|
||||
]
|
||||
});
|
||||
@@ -43,53 +45,53 @@ describe("unittests:: tsc-watch:: forceConsistentCasingInFileNames", () => {
|
||||
changes: [
|
||||
{
|
||||
caption: "Change name of file from logger to Logger",
|
||||
change: sys => sys.renameFile(loggerFile.path, `${ts.tscWatch.projectRoot}/Logger.ts`),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks,
|
||||
change: sys => sys.renameFile(loggerFile.path, `/user/username/projects/myproject/Logger.ts`),
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "forceConsistentCasingInFileNames",
|
||||
subScenario: "when relative information file location changes",
|
||||
commandLineArgs: ["--w", "--p", ".", "--explainFiles"],
|
||||
sys: () => {
|
||||
const moduleA: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/moduleA.ts`,
|
||||
const moduleA: File = {
|
||||
path: `/user/username/projects/myproject/moduleA.ts`,
|
||||
content: `import a = require("./ModuleC")`
|
||||
};
|
||||
const moduleB: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/moduleB.ts`,
|
||||
const moduleB: File = {
|
||||
path: `/user/username/projects/myproject/moduleB.ts`,
|
||||
content: `import a = require("./moduleC")`
|
||||
};
|
||||
const moduleC: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/moduleC.ts`,
|
||||
const moduleC: File = {
|
||||
path: `/user/username/projects/myproject/moduleC.ts`,
|
||||
content: `export const x = 10;`
|
||||
};
|
||||
const tsconfig: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const tsconfig: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: JSON.stringify({ compilerOptions: { forceConsistentCasingInFileNames: true } })
|
||||
};
|
||||
return ts.tscWatch.createWatchedSystem([moduleA, moduleB, moduleC, ts.tscWatch.libFile, tsconfig], { currentDirectory: ts.tscWatch.projectRoot });
|
||||
return createWatchedSystem([moduleA, moduleB, moduleC, libFile, tsconfig], { currentDirectory: "/user/username/projects/myproject" });
|
||||
},
|
||||
changes: [
|
||||
{
|
||||
caption: "Prepend a line to moduleA",
|
||||
change: sys => sys.prependFile(`${ts.tscWatch.projectRoot}/moduleA.ts`, `// some comment
|
||||
change: sys => sys.prependFile(`/user/username/projects/myproject/moduleA.ts`, `// some comment
|
||||
`),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks,
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "forceConsistentCasingInFileNames",
|
||||
subScenario: "jsxImportSource option changed",
|
||||
commandLineArgs: ["--w", "--p", ".", "--explainFiles"],
|
||||
sys: () => ts.tscWatch.createWatchedSystem([
|
||||
ts.tscWatch.libFile,
|
||||
sys: () => createWatchedSystem([
|
||||
libFile,
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/react/Jsx-runtime/index.d.ts`,
|
||||
path: `/user/username/projects/myproject/node_modules/react/Jsx-runtime/index.d.ts`,
|
||||
content: `export namespace JSX {
|
||||
interface Element {}
|
||||
interface IntrinsicElements {
|
||||
@@ -104,38 +106,38 @@ export const Fragment: unique symbol;
|
||||
`,
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/react/package.json`,
|
||||
path: `/user/username/projects/myproject/node_modules/react/package.json`,
|
||||
content: JSON.stringify({ name: "react", version: "0.0.1" })
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/index.tsx`,
|
||||
path: `/user/username/projects/myproject/index.tsx`,
|
||||
content: `export const App = () => <div propA={true}></div>;`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { jsx: "react-jsx", jsxImportSource: "react", forceConsistentCasingInFileNames: true },
|
||||
files: ["node_modules/react/Jsx-Runtime/index.d.ts", "index.tsx"]
|
||||
})
|
||||
}
|
||||
], { currentDirectory: ts.tscWatch.projectRoot }),
|
||||
], { currentDirectory: "/user/username/projects/myproject" }),
|
||||
changes: ts.emptyArray,
|
||||
});
|
||||
|
||||
function verifyWindowsStyleRoot(subScenario: string, windowsStyleRoot: string, projectRootRelative: string) {
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "forceConsistentCasingInFileNames",
|
||||
subScenario,
|
||||
commandLineArgs: ["--w", "--p", `${windowsStyleRoot}/${projectRootRelative}`, "--explainFiles"],
|
||||
sys: () => {
|
||||
const moduleA: ts.tscWatch.File = {
|
||||
const moduleA: File = {
|
||||
path: `${windowsStyleRoot}/${projectRootRelative}/a.ts`,
|
||||
content: `
|
||||
export const a = 1;
|
||||
export const b = 2;
|
||||
`
|
||||
};
|
||||
const moduleB: ts.tscWatch.File = {
|
||||
const moduleB: File = {
|
||||
path: `${windowsStyleRoot}/${projectRootRelative}/b.ts`,
|
||||
content: `
|
||||
import { a } from "${windowsStyleRoot.toLocaleUpperCase()}/${projectRootRelative}/a"
|
||||
@@ -144,18 +146,18 @@ import { b } from "${windowsStyleRoot.toLocaleLowerCase()}/${projectRootRelative
|
||||
a;b;
|
||||
`
|
||||
};
|
||||
const tsconfig: ts.tscWatch.File = {
|
||||
const tsconfig: File = {
|
||||
path: `${windowsStyleRoot}/${projectRootRelative}/tsconfig.json`,
|
||||
content: JSON.stringify({ compilerOptions: { forceConsistentCasingInFileNames: true } })
|
||||
};
|
||||
return ts.tscWatch.createWatchedSystem([moduleA, moduleB, ts.tscWatch.libFile, tsconfig], { windowsStyleRoot, useCaseSensitiveFileNames: false });
|
||||
return createWatchedSystem([moduleA, moduleB, libFile, tsconfig], { windowsStyleRoot, useCaseSensitiveFileNames: false });
|
||||
},
|
||||
changes: [
|
||||
{
|
||||
caption: "Prepend a line to moduleA",
|
||||
change: sys => sys.prependFile(`${windowsStyleRoot}/${projectRootRelative}/a.ts`, `// some comment
|
||||
`),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks,
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
}
|
||||
],
|
||||
});
|
||||
@@ -165,12 +167,12 @@ a;b;
|
||||
verifyWindowsStyleRoot("when Windows-style drive root is uppercase", "C:/", "project");
|
||||
|
||||
function verifyFileSymlink(subScenario: string, diskPath: string, targetPath: string, importedPath: string) {
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "forceConsistentCasingInFileNames",
|
||||
subScenario,
|
||||
commandLineArgs: ["--w", "--p", ".", "--explainFiles"],
|
||||
sys: () => {
|
||||
const moduleA: ts.tscWatch.File = {
|
||||
const moduleA: File = {
|
||||
|
||||
path: diskPath,
|
||||
content: `
|
||||
@@ -178,12 +180,12 @@ export const a = 1;
|
||||
export const b = 2;
|
||||
`
|
||||
};
|
||||
const symlinkA: ts.tscWatch.SymLink = {
|
||||
path: `${ts.tscWatch.projectRoot}/link.ts`,
|
||||
const symlinkA: SymLink = {
|
||||
path: `/user/username/projects/myproject/link.ts`,
|
||||
symLink: targetPath,
|
||||
};
|
||||
const moduleB: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/b.ts`,
|
||||
const moduleB: File = {
|
||||
path: `/user/username/projects/myproject/b.ts`,
|
||||
content: `
|
||||
import { a } from "${importedPath}";
|
||||
import { b } from "./link";
|
||||
@@ -191,36 +193,36 @@ import { b } from "./link";
|
||||
a;b;
|
||||
`
|
||||
};
|
||||
const tsconfig: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const tsconfig: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: JSON.stringify({ compilerOptions: { forceConsistentCasingInFileNames: true } })
|
||||
};
|
||||
return ts.tscWatch.createWatchedSystem([moduleA, symlinkA, moduleB, ts.tscWatch.libFile, tsconfig], { currentDirectory: ts.tscWatch.projectRoot });
|
||||
return createWatchedSystem([moduleA, symlinkA, moduleB, libFile, tsconfig], { currentDirectory: "/user/username/projects/myproject" });
|
||||
},
|
||||
changes: [
|
||||
{
|
||||
caption: "Prepend a line to moduleA",
|
||||
change: sys => sys.prependFile(diskPath, `// some comment
|
||||
`),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks,
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
}
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
verifyFileSymlink("when both file symlink target and import match disk", `${ts.tscWatch.projectRoot}/XY.ts`, `${ts.tscWatch.projectRoot}/XY.ts`, `./XY`);
|
||||
verifyFileSymlink("when file symlink target matches disk but import does not", `${ts.tscWatch.projectRoot}/XY.ts`, `${ts.tscWatch.projectRoot}/Xy.ts`, `./XY`);
|
||||
verifyFileSymlink("when import matches disk but file symlink target does not", `${ts.tscWatch.projectRoot}/XY.ts`, `${ts.tscWatch.projectRoot}/XY.ts`, `./Xy`);
|
||||
verifyFileSymlink("when import and file symlink target agree but do not match disk", `${ts.tscWatch.projectRoot}/XY.ts`, `${ts.tscWatch.projectRoot}/Xy.ts`, `./Xy`);
|
||||
verifyFileSymlink("when import, file symlink target, and disk are all different", `${ts.tscWatch.projectRoot}/XY.ts`, `${ts.tscWatch.projectRoot}/Xy.ts`, `./yX`);
|
||||
verifyFileSymlink("when both file symlink target and import match disk", `/user/username/projects/myproject/XY.ts`, `/user/username/projects/myproject/XY.ts`, `./XY`);
|
||||
verifyFileSymlink("when file symlink target matches disk but import does not", `/user/username/projects/myproject/XY.ts`, `/user/username/projects/myproject/Xy.ts`, `./XY`);
|
||||
verifyFileSymlink("when import matches disk but file symlink target does not", `/user/username/projects/myproject/XY.ts`, `/user/username/projects/myproject/XY.ts`, `./Xy`);
|
||||
verifyFileSymlink("when import and file symlink target agree but do not match disk", `/user/username/projects/myproject/XY.ts`, `/user/username/projects/myproject/Xy.ts`, `./Xy`);
|
||||
verifyFileSymlink("when import, file symlink target, and disk are all different", `/user/username/projects/myproject/XY.ts`, `/user/username/projects/myproject/Xy.ts`, `./yX`);
|
||||
|
||||
function verifyDirSymlink(subScenario: string, diskPath: string, targetPath: string, importedPath: string) {
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "forceConsistentCasingInFileNames",
|
||||
subScenario,
|
||||
commandLineArgs: ["--w", "--p", ".", "--explainFiles"],
|
||||
sys: () => {
|
||||
const moduleA: ts.tscWatch.File = {
|
||||
const moduleA: File = {
|
||||
|
||||
path: `${diskPath}/a.ts`,
|
||||
content: `
|
||||
@@ -228,12 +230,12 @@ export const a = 1;
|
||||
export const b = 2;
|
||||
`
|
||||
};
|
||||
const symlinkA: ts.tscWatch.SymLink = {
|
||||
path: `${ts.tscWatch.projectRoot}/link`,
|
||||
const symlinkA: SymLink = {
|
||||
path: `/user/username/projects/myproject/link`,
|
||||
symLink: targetPath,
|
||||
};
|
||||
const moduleB: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/b.ts`,
|
||||
const moduleB: File = {
|
||||
path: `/user/username/projects/myproject/b.ts`,
|
||||
content: `
|
||||
import { a } from "${importedPath}/a";
|
||||
import { b } from "./link/a";
|
||||
@@ -241,35 +243,35 @@ import { b } from "./link/a";
|
||||
a;b;
|
||||
`
|
||||
};
|
||||
const tsconfig: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const tsconfig: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
// Use outFile because otherwise the real and linked files will have the same output path
|
||||
content: JSON.stringify({ compilerOptions: { forceConsistentCasingInFileNames: true, outFile: "out.js", module: "system" } })
|
||||
};
|
||||
return ts.tscWatch.createWatchedSystem([moduleA, symlinkA, moduleB, ts.tscWatch.libFile, tsconfig], { currentDirectory: ts.tscWatch.projectRoot });
|
||||
return createWatchedSystem([moduleA, symlinkA, moduleB, libFile, tsconfig], { currentDirectory: "/user/username/projects/myproject" });
|
||||
},
|
||||
changes: [
|
||||
{
|
||||
caption: "Prepend a line to moduleA",
|
||||
change: sys => sys.prependFile(`${diskPath}/a.ts`, `// some comment
|
||||
`),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks,
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
}
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
verifyDirSymlink("when both directory symlink target and import match disk", `${ts.tscWatch.projectRoot}/XY`, `${ts.tscWatch.projectRoot}/XY`, `./XY`);
|
||||
verifyDirSymlink("when directory symlink target matches disk but import does not", `${ts.tscWatch.projectRoot}/XY`, `${ts.tscWatch.projectRoot}/Xy`, `./XY`);
|
||||
verifyDirSymlink("when import matches disk but directory symlink target does not", `${ts.tscWatch.projectRoot}/XY`, `${ts.tscWatch.projectRoot}/XY`, `./Xy`);
|
||||
verifyDirSymlink("when import and directory symlink target agree but do not match disk", `${ts.tscWatch.projectRoot}/XY`, `${ts.tscWatch.projectRoot}/Xy`, `./Xy`);
|
||||
verifyDirSymlink("when import, directory symlink target, and disk are all different", `${ts.tscWatch.projectRoot}/XY`, `${ts.tscWatch.projectRoot}/Xy`, `./yX`);
|
||||
verifyDirSymlink("when both directory symlink target and import match disk", `/user/username/projects/myproject/XY`, `/user/username/projects/myproject/XY`, `./XY`);
|
||||
verifyDirSymlink("when directory symlink target matches disk but import does not", `/user/username/projects/myproject/XY`, `/user/username/projects/myproject/Xy`, `./XY`);
|
||||
verifyDirSymlink("when import matches disk but directory symlink target does not", `/user/username/projects/myproject/XY`, `/user/username/projects/myproject/XY`, `./Xy`);
|
||||
verifyDirSymlink("when import and directory symlink target agree but do not match disk", `/user/username/projects/myproject/XY`, `/user/username/projects/myproject/Xy`, `./Xy`);
|
||||
verifyDirSymlink("when import, directory symlink target, and disk are all different", `/user/username/projects/myproject/XY`, `/user/username/projects/myproject/Xy`, `./yX`);
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "forceConsistentCasingInFileNames",
|
||||
subScenario: "with nodeNext resolution",
|
||||
commandLineArgs: ["--w", "--explainFiles"],
|
||||
sys: () => ts.tscWatch.createWatchedSystem({
|
||||
sys: () => createWatchedSystem({
|
||||
"/Users/name/projects/web/src/bin.ts": `import { foo } from "yargs";`,
|
||||
"/Users/name/projects/web/node_modules/@types/yargs/index.d.ts": "export function foo(): void;",
|
||||
"/Users/name/projects/web/node_modules/@types/yargs/index.d.mts": "export function foo(): void;",
|
||||
@@ -292,16 +294,16 @@ a;b;
|
||||
traceResolution: true,
|
||||
}
|
||||
}),
|
||||
[ts.tscWatch.libFile.path]: ts.tscWatch.libFile.content,
|
||||
[libFile.path]: libFile.content,
|
||||
}, { currentDirectory: "/Users/name/projects/web" }),
|
||||
changes: ts.emptyArray,
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "forceConsistentCasingInFileNames",
|
||||
subScenario: "self name package reference",
|
||||
commandLineArgs: ["-w", "--explainFiles"],
|
||||
sys: () => ts.tscWatch.createWatchedSystem({
|
||||
sys: () => createWatchedSystem({
|
||||
"/Users/name/projects/web/package.json": JSON.stringify({
|
||||
name: "@this/package",
|
||||
type: "module",
|
||||
@@ -324,17 +326,17 @@ a;b;
|
||||
traceResolution: true,
|
||||
}
|
||||
}),
|
||||
"/a/lib/lib.esnext.full.d.ts": ts.tscWatch.libFile.content,
|
||||
"/a/lib/lib.esnext.full.d.ts": libFile.content,
|
||||
}, { currentDirectory: "/Users/name/projects/web" }),
|
||||
changes: ts.emptyArray,
|
||||
});
|
||||
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "forceConsistentCasingInFileNames",
|
||||
subScenario: "package json is looked up for file",
|
||||
commandLineArgs: ["-w", "--explainFiles"],
|
||||
sys: () => ts.tscWatch.createWatchedSystem({
|
||||
sys: () => createWatchedSystem({
|
||||
"/Users/name/projects/lib-boilerplate/package.json": JSON.stringify({
|
||||
name: "lib-boilerplate",
|
||||
version: "0.0.2",
|
||||
@@ -355,7 +357,7 @@ a;b;
|
||||
traceResolution: true,
|
||||
}
|
||||
}),
|
||||
"/a/lib/lib.es2021.full.d.ts": ts.tscWatch.libFile.content,
|
||||
"/a/lib/lib.es2021.full.d.ts": libFile.content,
|
||||
}, { currentDirectory: "/Users/name/projects/lib-boilerplate" }),
|
||||
changes: ts.emptyArray,
|
||||
});
|
||||
|
||||
@@ -1,17 +1,8 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as fakes from "../../_namespaces/fakes";
|
||||
import * as Harness from "../../_namespaces/Harness";
|
||||
|
||||
export const projects = `/user/username/projects`;
|
||||
export const projectRoot = `${projects}/myproject`;
|
||||
export import WatchedSystem = ts.TestFSWithWatch.TestServerHost;
|
||||
export type File = ts.TestFSWithWatch.File;
|
||||
export type SymLink = ts.TestFSWithWatch.SymLink;
|
||||
export import libFile = ts.TestFSWithWatch.libFile;
|
||||
export import createWatchedSystem = ts.TestFSWithWatch.createWatchedSystem;
|
||||
export import checkArray = ts.TestFSWithWatch.checkArray;
|
||||
export import checkOutputContains = ts.TestFSWithWatch.checkOutputContains;
|
||||
export import checkOutputDoesNotContain = ts.TestFSWithWatch.checkOutputDoesNotContain;
|
||||
import { patchHostForBuildInfoReadWrite } from "../../_namespaces/fakes";
|
||||
import { Baseline } from "../../_namespaces/Harness";
|
||||
import { changeToHostTrackingWrittenFiles, createWatchedSystem, File, FileOrFolderOrSymLink, FileOrFolderOrSymLinkMap, TestServerHost, TestServerHostCreationParameters, TestServerHostTrackingWrittenFiles } from "../virtualFileSystemWithWatch";
|
||||
import { baselinePrograms, commandLineCallbacks, CommandLineCallbacks, CommandLineProgram, createSolutionBuilderHostForBaseline, generateSourceMapBaselineFiles } from "../tsc/helpers";
|
||||
|
||||
export const commonFile1: File = {
|
||||
path: "/a/b/commonFile1.ts",
|
||||
@@ -22,89 +13,13 @@ export const commonFile2: File = {
|
||||
content: "let y = 1"
|
||||
};
|
||||
|
||||
export function checkProgramActualFiles(program: ts.Program, expectedFiles: readonly string[]) {
|
||||
checkArray(`Program actual files`, program.getSourceFiles().map(file => file.fileName), expectedFiles);
|
||||
}
|
||||
|
||||
export function getDiagnosticMessageChain(message: ts.DiagnosticMessage, args?: (string | number)[], next?: ts.DiagnosticMessageChain[]): ts.DiagnosticMessageChain {
|
||||
let text = ts.getLocaleSpecificMessage(message);
|
||||
if (args?.length) {
|
||||
text = ts.formatStringFromArgs(text, args);
|
||||
}
|
||||
return {
|
||||
messageText: text,
|
||||
category: message.category,
|
||||
code: message.code,
|
||||
next
|
||||
};
|
||||
}
|
||||
|
||||
function isDiagnosticMessageChain(message: ts.DiagnosticMessage | ts.DiagnosticMessageChain): message is ts.DiagnosticMessageChain {
|
||||
return !!(message as ts.DiagnosticMessageChain).messageText;
|
||||
}
|
||||
|
||||
export function getDiagnosticOfFileFrom(file: ts.SourceFile | undefined, start: number | undefined, length: number | undefined, message: ts.DiagnosticMessage | ts.DiagnosticMessageChain, ...args: (string | number)[]): ts.Diagnostic {
|
||||
return {
|
||||
file,
|
||||
start,
|
||||
length,
|
||||
|
||||
messageText: isDiagnosticMessageChain(message) ?
|
||||
message :
|
||||
getDiagnosticMessageChain(message, args).messageText,
|
||||
category: message.category,
|
||||
code: message.code,
|
||||
};
|
||||
}
|
||||
|
||||
export function getDiagnosticWithoutFile(message: ts.DiagnosticMessage | ts.DiagnosticMessageChain, ...args: (string | number)[]): ts.Diagnostic {
|
||||
return getDiagnosticOfFileFrom(/*file*/ undefined, /*start*/ undefined, /*length*/ undefined, message, ...args);
|
||||
}
|
||||
|
||||
export function getDiagnosticOfFile(file: ts.SourceFile, start: number, length: number, message: ts.DiagnosticMessage | ts.DiagnosticMessageChain, ...args: (string | number)[]): ts.Diagnostic {
|
||||
return getDiagnosticOfFileFrom(file, start, length, message, ...args);
|
||||
}
|
||||
|
||||
export function getDiagnosticOfFileFromProgram(program: ts.Program, filePath: string, start: number, length: number, message: ts.DiagnosticMessage | ts.DiagnosticMessageChain, ...args: (string | number)[]): ts.Diagnostic {
|
||||
return getDiagnosticOfFileFrom(program.getSourceFileByPath(ts.toPath(filePath, program.getCurrentDirectory(), s => s.toLowerCase())),
|
||||
start, length, message, ...args);
|
||||
}
|
||||
|
||||
export function getUnknownCompilerOption(program: ts.Program, configFile: File, option: string) {
|
||||
const quotedOption = `"${option}"`;
|
||||
return getDiagnosticOfFile(program.getCompilerOptions().configFile!, configFile.content.indexOf(quotedOption), quotedOption.length, ts.Diagnostics.Unknown_compiler_option_0, option);
|
||||
}
|
||||
|
||||
export function getUnknownDidYouMeanCompilerOption(program: ts.Program, configFile: File, option: string, didYouMean: string) {
|
||||
const quotedOption = `"${option}"`;
|
||||
return getDiagnosticOfFile(program.getCompilerOptions().configFile!, configFile.content.indexOf(quotedOption), quotedOption.length, ts.Diagnostics.Unknown_compiler_option_0_Did_you_mean_1, option, didYouMean);
|
||||
}
|
||||
|
||||
export function getDiagnosticModuleNotFoundOfFile(program: ts.Program, file: File, moduleName: string) {
|
||||
const quotedModuleName = `"${moduleName}"`;
|
||||
return getDiagnosticOfFileFromProgram(program, file.path, file.content.indexOf(quotedModuleName), quotedModuleName.length, ts.Diagnostics.Cannot_find_module_0_Did_you_mean_to_set_the_moduleResolution_option_to_node_or_to_add_aliases_to_the_paths_option, moduleName);
|
||||
}
|
||||
|
||||
export function runQueuedTimeoutCallbacks(sys: WatchedSystem) {
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
}
|
||||
|
||||
export function checkSingleTimeoutQueueLengthAndRun(sys: WatchedSystem) {
|
||||
sys.checkTimeoutQueueLengthAndRun(1);
|
||||
}
|
||||
|
||||
export function checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout(sys: WatchedSystem) {
|
||||
sys.checkTimeoutQueueLengthAndRun(1);
|
||||
sys.checkTimeoutQueueLength(0);
|
||||
}
|
||||
|
||||
export type WatchOrSolution<T extends ts.BuilderProgram> = void | ts.SolutionBuilder<T> | ts.WatchOfConfigFile<T> | ts.WatchOfFilesAndCompilerOptions<T>;
|
||||
export interface TscWatchCompileChange<T extends ts.BuilderProgram = ts.EmitAndSemanticDiagnosticsBuilderProgram> {
|
||||
caption: string;
|
||||
change: (sys: ts.TestFSWithWatch.TestServerHostTrackingWrittenFiles) => void;
|
||||
change: (sys: TestServerHostTrackingWrittenFiles) => void;
|
||||
timeouts: (
|
||||
sys: ts.TestFSWithWatch.TestServerHostTrackingWrittenFiles,
|
||||
programs: readonly ts.CommandLineProgram[],
|
||||
sys: TestServerHostTrackingWrittenFiles,
|
||||
programs: readonly CommandLineProgram[],
|
||||
watchOrSolution: WatchOrSolution<T>
|
||||
) => void;
|
||||
}
|
||||
@@ -119,7 +34,7 @@ export interface TscWatchCompileBase<T extends ts.BuilderProgram = ts.EmitAndSem
|
||||
changes: readonly TscWatchCompileChange<T>[];
|
||||
}
|
||||
export interface TscWatchCompile extends TscWatchCompileBase {
|
||||
sys: () => WatchedSystem;
|
||||
sys: () => TestServerHost;
|
||||
}
|
||||
|
||||
export const noopChange: TscWatchCompileChange = {
|
||||
@@ -128,7 +43,7 @@ export const noopChange: TscWatchCompileChange = {
|
||||
timeouts: sys => sys.checkTimeoutQueueLength(0),
|
||||
};
|
||||
|
||||
export type SystemSnap = ReturnType<WatchedSystem["snap"]>;
|
||||
export type SystemSnap = ReturnType<TestServerHost["snap"]>;
|
||||
function tscWatchCompile(input: TscWatchCompile) {
|
||||
it("tsc-watch:: Generates files matching the baseline", () => {
|
||||
const { sys, baseline, oldSnap } = createBaseline(input.sys());
|
||||
@@ -139,7 +54,7 @@ function tscWatchCompile(input: TscWatchCompile) {
|
||||
} = input;
|
||||
|
||||
if (!isWatch(commandLineArgs)) sys.exit = exitCode => sys.exitCode = exitCode;
|
||||
const { cb, getPrograms } = ts.commandLineCallbacks(sys);
|
||||
const { cb, getPrograms } = commandLineCallbacks(sys);
|
||||
const watchOrSolution = ts.executeCommandLine(
|
||||
sys,
|
||||
cb,
|
||||
@@ -163,26 +78,26 @@ function tscWatchCompile(input: TscWatchCompile) {
|
||||
|
||||
export interface BaselineBase {
|
||||
baseline: string[];
|
||||
sys: ts.TestFSWithWatch.TestServerHostTrackingWrittenFiles;
|
||||
sys: TestServerHostTrackingWrittenFiles;
|
||||
oldSnap: SystemSnap;
|
||||
}
|
||||
|
||||
export interface Baseline extends BaselineBase, ts.CommandLineCallbacks {
|
||||
export interface Baseline extends BaselineBase, CommandLineCallbacks {
|
||||
}
|
||||
|
||||
export function createBaseline(system: WatchedSystem, modifySystem?: (sys: WatchedSystem, originalRead: WatchedSystem["readFile"]) => void): Baseline {
|
||||
export function createBaseline(system: TestServerHost, modifySystem?: (sys: TestServerHost, originalRead: TestServerHost["readFile"]) => void): Baseline {
|
||||
const originalRead = system.readFile;
|
||||
const initialSys = fakes.patchHostForBuildInfoReadWrite(system);
|
||||
const initialSys = patchHostForBuildInfoReadWrite(system);
|
||||
modifySystem?.(initialSys, originalRead);
|
||||
const sys = ts.TestFSWithWatch.changeToHostTrackingWrittenFiles(initialSys);
|
||||
const sys = changeToHostTrackingWrittenFiles(initialSys);
|
||||
const baseline: string[] = [];
|
||||
baseline.push("Input::");
|
||||
sys.diff(baseline);
|
||||
const { cb, getPrograms } = ts.commandLineCallbacks(sys);
|
||||
const { cb, getPrograms } = commandLineCallbacks(sys);
|
||||
return { sys, baseline, oldSnap: sys.snap(), cb, getPrograms };
|
||||
}
|
||||
|
||||
export function createSolutionBuilderWithWatchHostForBaseline(sys: WatchedSystem, cb: ts.ExecuteCommandLineCallbacks) {
|
||||
export function createSolutionBuilderWithWatchHostForBaseline(sys: TestServerHost, cb: ts.ExecuteCommandLineCallbacks) {
|
||||
const host = ts.createSolutionBuilderWithWatchHost(sys,
|
||||
/*createProgram*/ undefined,
|
||||
ts.createDiagnosticReporter(sys, /*pretty*/ true),
|
||||
@@ -195,7 +110,7 @@ export function createSolutionBuilderWithWatchHostForBaseline(sys: WatchedSystem
|
||||
}
|
||||
|
||||
interface CreateWatchCompilerHostOfConfigFileForBaseline<T extends ts.BuilderProgram> extends ts.CreateWatchCompilerHostOfConfigFileInput<T> {
|
||||
system: WatchedSystem,
|
||||
system: TestServerHost,
|
||||
cb: ts.ExecuteCommandLineCallbacks;
|
||||
}
|
||||
|
||||
@@ -212,7 +127,7 @@ export function createWatchCompilerHostOfConfigFileForBaseline<T extends ts.Buil
|
||||
}
|
||||
|
||||
interface CreateWatchCompilerHostOfFilesAndCompilerOptionsForBaseline<T extends ts.BuilderProgram> extends ts.CreateWatchCompilerHostOfFilesAndCompilerOptionsInput<T> {
|
||||
system: WatchedSystem,
|
||||
system: TestServerHost,
|
||||
cb: ts.ExecuteCommandLineCallbacks;
|
||||
}
|
||||
export function createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline<T extends ts.BuilderProgram = ts.EmitAndSemanticDiagnosticsBuilderProgram>(
|
||||
@@ -246,8 +161,8 @@ export function applyChange(sys: BaselineBase["sys"], baseline: BaselineBase["ba
|
||||
}
|
||||
|
||||
export interface RunWatchBaseline<T extends ts.BuilderProgram> extends BaselineBase, TscWatchCompileBase<T> {
|
||||
sys: ts.TestFSWithWatch.TestServerHostTrackingWrittenFiles;
|
||||
getPrograms: () => readonly ts.CommandLineProgram[];
|
||||
sys: TestServerHostTrackingWrittenFiles;
|
||||
getPrograms: () => readonly CommandLineProgram[];
|
||||
watchOrSolution: WatchOrSolution<T>;
|
||||
}
|
||||
export function runWatchBaseline<T extends ts.BuilderProgram = ts.EmitAndSemanticDiagnosticsBuilderProgram>({
|
||||
@@ -280,7 +195,7 @@ export function runWatchBaseline<T extends ts.BuilderProgram = ts.EmitAndSemanti
|
||||
baselineDependencies,
|
||||
});
|
||||
}
|
||||
Harness.Baseline.runBaseline(`${ts.isBuild(commandLineArgs) ? "tsbuild" : "tsc"}${isWatch(commandLineArgs) ? "Watch" : ""}/${scenario}/${subScenario.split(" ").join("-")}.js`, baseline.join("\r\n"));
|
||||
Baseline.runBaseline(`${ts.isBuild(commandLineArgs) ? "tsbuild" : "tsc"}${isWatch(commandLineArgs) ? "Watch" : ""}/${scenario}/${subScenario.split(" ").join("-")}.js`, baseline.join("\r\n"));
|
||||
}
|
||||
|
||||
function isWatch(commandLineArgs: readonly string[]) {
|
||||
@@ -292,11 +207,11 @@ function isWatch(commandLineArgs: readonly string[]) {
|
||||
}
|
||||
|
||||
export interface WatchBaseline extends BaselineBase, TscWatchCheckOptions {
|
||||
oldPrograms: readonly (ts.CommandLineProgram | undefined)[];
|
||||
getPrograms: () => readonly ts.CommandLineProgram[];
|
||||
oldPrograms: readonly (CommandLineProgram | undefined)[];
|
||||
getPrograms: () => readonly CommandLineProgram[];
|
||||
}
|
||||
export function watchBaseline({ baseline, getPrograms, oldPrograms, sys, oldSnap, baselineSourceMap, baselineDependencies }: WatchBaseline) {
|
||||
if (baselineSourceMap) ts.generateSourceMapBaselineFiles(sys);
|
||||
if (baselineSourceMap) generateSourceMapBaselineFiles(sys);
|
||||
sys.serializeOutput(baseline);
|
||||
const programs = baselinePrograms(baseline, getPrograms, oldPrograms, baselineDependencies);
|
||||
sys.serializeWatches(baseline);
|
||||
@@ -308,83 +223,6 @@ export function watchBaseline({ baseline, getPrograms, oldPrograms, sys, oldSnap
|
||||
sys.writtenFiles.clear();
|
||||
return programs;
|
||||
}
|
||||
|
||||
export function baselinePrograms(baseline: string[], getPrograms: () => readonly ts.CommandLineProgram[], oldPrograms: readonly (ts.CommandLineProgram | undefined)[], baselineDependencies: boolean | undefined) {
|
||||
const programs = getPrograms();
|
||||
for (let i = 0; i < programs.length; i++) {
|
||||
baselineProgram(baseline, programs[i], oldPrograms[i], baselineDependencies);
|
||||
}
|
||||
return programs;
|
||||
}
|
||||
|
||||
function baselineProgram(baseline: string[], [program, builderProgram]: ts.CommandLineProgram, oldProgram: ts.CommandLineProgram | undefined, baselineDependencies: boolean | undefined) {
|
||||
if (program !== oldProgram?.[0]) {
|
||||
const options = program.getCompilerOptions();
|
||||
baseline.push(`Program root files: ${JSON.stringify(program.getRootFileNames())}`);
|
||||
baseline.push(`Program options: ${JSON.stringify(options)}`);
|
||||
baseline.push(`Program structureReused: ${(ts as any).StructureIsReused[program.structureIsReused]}`);
|
||||
baseline.push("Program files::");
|
||||
for (const file of program.getSourceFiles()) {
|
||||
baseline.push(file.fileName);
|
||||
}
|
||||
}
|
||||
else {
|
||||
baseline.push(`Program: Same as old program`);
|
||||
}
|
||||
baseline.push("");
|
||||
|
||||
if (!builderProgram) return;
|
||||
if (builderProgram !== oldProgram?.[1]) {
|
||||
const state = builderProgram.getState();
|
||||
const internalState = state as unknown as ts.BuilderProgramState;
|
||||
if (state.semanticDiagnosticsPerFile?.size) {
|
||||
baseline.push("Semantic diagnostics in builder refreshed for::");
|
||||
for (const file of program.getSourceFiles()) {
|
||||
if (!internalState.semanticDiagnosticsFromOldState || !internalState.semanticDiagnosticsFromOldState.has(file.resolvedPath)) {
|
||||
baseline.push(file.fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
baseline.push("No cached semantic diagnostics in the builder::");
|
||||
}
|
||||
if (internalState) {
|
||||
baseline.push("");
|
||||
if (internalState.hasCalledUpdateShapeSignature?.size) {
|
||||
baseline.push("Shape signatures in builder refreshed for::");
|
||||
internalState.hasCalledUpdateShapeSignature.forEach((path: ts.Path) => {
|
||||
const info = state.fileInfos.get(path);
|
||||
if (info?.version === info?.signature || !info?.signature) {
|
||||
baseline.push(path + " (used version)");
|
||||
}
|
||||
else if (internalState.filesChangingSignature?.has(path)) {
|
||||
baseline.push(path + " (computed .d.ts during emit)");
|
||||
}
|
||||
else {
|
||||
baseline.push(path + " (computed .d.ts)");
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
baseline.push("No shapes updated in the builder::");
|
||||
}
|
||||
}
|
||||
baseline.push("");
|
||||
if (!baselineDependencies) return;
|
||||
baseline.push("Dependencies for::");
|
||||
for (const file of builderProgram.getSourceFiles()) {
|
||||
baseline.push(`${file.fileName}:`);
|
||||
for (const depenedency of builderProgram.getAllDependencies(file)) {
|
||||
baseline.push(` ${depenedency}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
baseline.push(`BuilderProgram: Same as old builder program`);
|
||||
}
|
||||
baseline.push("");
|
||||
}
|
||||
|
||||
export interface VerifyTscWatch extends TscWatchCompile {
|
||||
baselineIncremental?: boolean;
|
||||
}
|
||||
@@ -405,28 +243,23 @@ export function verifyTscWatch(input: VerifyTscWatch) {
|
||||
});
|
||||
}
|
||||
|
||||
export function replaceFileText(sys: WatchedSystem, file: string, searchValue: string | RegExp, replaceValue: string) {
|
||||
const content = ts.Debug.checkDefined(sys.readFile(file));
|
||||
sys.writeFile(file, content.replace(searchValue, replaceValue));
|
||||
}
|
||||
|
||||
export function createSolutionBuilder(system: WatchedSystem, rootNames: readonly string[], originalRead?: WatchedSystem["readFile"]) {
|
||||
const host = ts.createSolutionBuilderHostForBaseline(system, /*versionToWrite*/ undefined, originalRead);
|
||||
export function createSolutionBuilder(system: TestServerHost, rootNames: readonly string[], originalRead?: TestServerHost["readFile"]) {
|
||||
const host = createSolutionBuilderHostForBaseline(system, /*versionToWrite*/ undefined, originalRead);
|
||||
return ts.createSolutionBuilder(host, rootNames, {});
|
||||
}
|
||||
|
||||
export function ensureErrorFreeBuild(host: WatchedSystem, rootNames: readonly string[]) {
|
||||
export function ensureErrorFreeBuild(host: TestServerHost, rootNames: readonly string[]) {
|
||||
// ts build should succeed
|
||||
solutionBuildWithBaseline(host, rootNames);
|
||||
assert.equal(host.getOutput().length, 0, JSON.stringify(host.getOutput(), /*replacer*/ undefined, " "));
|
||||
}
|
||||
|
||||
export function solutionBuildWithBaseline(sys: WatchedSystem, solutionRoots: readonly string[], originalRead?: WatchedSystem["readFile"]) {
|
||||
export function solutionBuildWithBaseline(sys: TestServerHost, solutionRoots: readonly string[], originalRead?: TestServerHost["readFile"]) {
|
||||
const originalReadFile = sys.readFile;
|
||||
const originalWrite = sys.write;
|
||||
const originalWriteFile = sys.writeFile;
|
||||
const solutionBuilder = createSolutionBuilder(ts.TestFSWithWatch.changeToHostTrackingWrittenFiles(
|
||||
fakes.patchHostForBuildInfoReadWrite(sys)
|
||||
const solutionBuilder = createSolutionBuilder(changeToHostTrackingWrittenFiles(
|
||||
patchHostForBuildInfoReadWrite(sys)
|
||||
), solutionRoots, originalRead);
|
||||
solutionBuilder.build();
|
||||
sys.readFile = originalReadFile;
|
||||
@@ -435,6 +268,6 @@ export function solutionBuildWithBaseline(sys: WatchedSystem, solutionRoots: rea
|
||||
return sys;
|
||||
}
|
||||
|
||||
export function createSystemWithSolutionBuild(solutionRoots: readonly string[], files: ts.TestFSWithWatch.FileOrFolderOrSymLinkMap | readonly ts.TestFSWithWatch.FileOrFolderOrSymLink[], params?: ts.TestFSWithWatch.TestServerHostCreationParameters) {
|
||||
export function createSystemWithSolutionBuild(solutionRoots: readonly string[], files: FileOrFolderOrSymLinkMap | readonly FileOrFolderOrSymLink[], params?: TestServerHostCreationParameters) {
|
||||
return solutionBuildWithBaseline(createWatchedSystem(files, params), solutionRoots);
|
||||
}
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as Harness from "../../_namespaces/Harness";
|
||||
import { createWatchedSystem, File, libFile, TestServerHost } from "../virtualFileSystemWithWatch";
|
||||
import { CommandLineProgram, libContent } from "../tsc/helpers";
|
||||
import { applyChange, createBaseline, SystemSnap, verifyTscWatch, watchBaseline } from "./helpers";
|
||||
|
||||
describe("unittests:: tsc-watch:: emit file --incremental", () => {
|
||||
const project = "/users/username/projects/project";
|
||||
|
||||
const configFile: ts.tscWatch.File = {
|
||||
const configFile: File = {
|
||||
path: `${project}/tsconfig.json`,
|
||||
content: JSON.stringify({ compilerOptions: { incremental: true } })
|
||||
};
|
||||
|
||||
interface VerifyIncrementalWatchEmitInput {
|
||||
subScenario: string;
|
||||
files: () => readonly ts.tscWatch.File[];
|
||||
files: () => readonly File[];
|
||||
optionsToExtend?: readonly string[];
|
||||
modifyFs?: (host: ts.tscWatch.WatchedSystem) => void;
|
||||
modifyFs?: (host: TestServerHost) => void;
|
||||
}
|
||||
function verifyIncrementalWatchEmit(input: VerifyIncrementalWatchEmitInput) {
|
||||
describe(input.subScenario, () => {
|
||||
@@ -30,27 +33,27 @@ describe("unittests:: tsc-watch:: emit file --incremental", () => {
|
||||
{ subScenario, files, optionsToExtend, modifyFs }: VerifyIncrementalWatchEmitInput,
|
||||
incremental: boolean
|
||||
) {
|
||||
const { sys, baseline, oldSnap, cb, getPrograms } = ts.tscWatch.createBaseline(ts.tscWatch.createWatchedSystem(files(), { currentDirectory: project }));
|
||||
const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem(files(), { currentDirectory: project }));
|
||||
if (incremental) sys.exit = exitCode => sys.exitCode = exitCode;
|
||||
const argsToPass = [incremental ? "-i" : "-w", ...(optionsToExtend || ts.emptyArray)];
|
||||
baseline.push(`${sys.getExecutingFilePath()} ${argsToPass.join(" ")}`);
|
||||
let oldPrograms: readonly ts.CommandLineProgram[] = ts.emptyArray;
|
||||
let oldPrograms: readonly CommandLineProgram[] = ts.emptyArray;
|
||||
build(oldSnap);
|
||||
|
||||
if (modifyFs) {
|
||||
const oldSnap = ts.tscWatch.applyChange(sys, baseline, modifyFs);
|
||||
const oldSnap = applyChange(sys, baseline, modifyFs);
|
||||
build(oldSnap);
|
||||
}
|
||||
|
||||
Harness.Baseline.runBaseline(`${ts.isBuild(argsToPass) ? "tsbuild/watchMode" : "tscWatch"}/incremental/${subScenario.split(" ").join("-")}-${incremental ? "incremental" : "watch"}.js`, baseline.join("\r\n"));
|
||||
|
||||
function build(oldSnap: ts.tscWatch.SystemSnap) {
|
||||
function build(oldSnap: SystemSnap) {
|
||||
const closer = ts.executeCommandLine(
|
||||
sys,
|
||||
cb,
|
||||
argsToPass,
|
||||
);
|
||||
oldPrograms = ts.tscWatch.watchBaseline({
|
||||
oldPrograms = watchBaseline({
|
||||
baseline,
|
||||
getPrograms,
|
||||
oldPrograms,
|
||||
@@ -62,11 +65,11 @@ describe("unittests:: tsc-watch:: emit file --incremental", () => {
|
||||
}
|
||||
|
||||
describe("non module compilation", () => {
|
||||
const file1: ts.tscWatch.File = {
|
||||
const file1: File = {
|
||||
path: `${project}/file1.ts`,
|
||||
content: "const x = 10;"
|
||||
};
|
||||
const file2: ts.tscWatch.File = {
|
||||
const file2: File = {
|
||||
path: `${project}/file2.ts`,
|
||||
content: "const y = 20;"
|
||||
};
|
||||
@@ -74,7 +77,7 @@ describe("unittests:: tsc-watch:: emit file --incremental", () => {
|
||||
function verify(subScenario: string, optionsToExtend?: readonly string[]) {
|
||||
const modifiedFile2Content = file2.content.replace("y", "z").replace("20", "10");
|
||||
verifyIncrementalWatchEmit({
|
||||
files: () => [ts.tscWatch.libFile, file1, file2, configFile],
|
||||
files: () => [libFile, file1, file2, configFile],
|
||||
optionsToExtend,
|
||||
subScenario: `own file emit without errors/${subScenario}`,
|
||||
modifyFs: host => host.writeFile(file2.path, modifiedFile2Content),
|
||||
@@ -85,7 +88,7 @@ describe("unittests:: tsc-watch:: emit file --incremental", () => {
|
||||
});
|
||||
|
||||
verifyIncrementalWatchEmit({
|
||||
files: () => [ts.tscWatch.libFile, file1, configFile, {
|
||||
files: () => [libFile, file1, configFile, {
|
||||
path: file2.path,
|
||||
content: `const y: string = 20;`
|
||||
}],
|
||||
@@ -94,7 +97,7 @@ describe("unittests:: tsc-watch:: emit file --incremental", () => {
|
||||
});
|
||||
|
||||
verifyIncrementalWatchEmit({
|
||||
files: () => [ts.tscWatch.libFile, file1, file2, {
|
||||
files: () => [libFile, file1, file2, {
|
||||
path: configFile.path,
|
||||
content: JSON.stringify({ compilerOptions: { incremental: true, outFile: "out.js" } })
|
||||
}],
|
||||
@@ -103,39 +106,39 @@ describe("unittests:: tsc-watch:: emit file --incremental", () => {
|
||||
});
|
||||
|
||||
describe("module compilation", () => {
|
||||
const file1: ts.tscWatch.File = {
|
||||
const file1: File = {
|
||||
path: `${project}/file1.ts`,
|
||||
content: "export const x = 10;"
|
||||
};
|
||||
const file2: ts.tscWatch.File = {
|
||||
const file2: File = {
|
||||
path: `${project}/file2.ts`,
|
||||
content: "export const y = 20;"
|
||||
};
|
||||
const config: ts.tscWatch.File = {
|
||||
const config: File = {
|
||||
path: configFile.path,
|
||||
content: JSON.stringify({ compilerOptions: { incremental: true, module: "amd" } })
|
||||
};
|
||||
|
||||
verifyIncrementalWatchEmit({
|
||||
files: () => [ts.tscWatch.libFile, file1, file2, config],
|
||||
files: () => [libFile, file1, file2, config],
|
||||
subScenario: "module compilation/own file emit without errors",
|
||||
modifyFs: host => host.writeFile(file2.path, file2.content.replace("y", "z").replace("20", "10")),
|
||||
});
|
||||
|
||||
describe("own file emit with errors", () => {
|
||||
const fileModified: ts.tscWatch.File = {
|
||||
const fileModified: File = {
|
||||
path: file2.path,
|
||||
content: `export const y: string = 20;`
|
||||
};
|
||||
|
||||
verifyIncrementalWatchEmit({
|
||||
files: () => [ts.tscWatch.libFile, file1, fileModified, config],
|
||||
files: () => [libFile, file1, fileModified, config],
|
||||
subScenario: "module compilation/own file emit with errors",
|
||||
modifyFs: host => host.writeFile(file1.path, file1.content.replace("x = 10", "z = 10")),
|
||||
});
|
||||
|
||||
it("verify that state is read correctly", () => {
|
||||
const system = ts.tscWatch.createWatchedSystem([ts.tscWatch.libFile, file1, fileModified, config], { currentDirectory: project });
|
||||
const system = createWatchedSystem([libFile, file1, fileModified, config], { currentDirectory: project });
|
||||
const reportDiagnostic = ts.createDiagnosticReporter(system);
|
||||
const parsedConfig = ts.parseConfigFileWithSystem("tsconfig.json", {}, /*extendedConfigCache*/ undefined, /*watchOptionsToExtend*/ undefined, system, reportDiagnostic)!;
|
||||
ts.performIncrementalCompilation({
|
||||
@@ -160,9 +163,9 @@ describe("unittests:: tsc-watch:: emit file --incremental", () => {
|
||||
assert.equal(state.changedFilesSet!.size, 0, "changes");
|
||||
|
||||
assert.equal(state.fileInfos.size, 3, "FileInfo size");
|
||||
assert.deepEqual(state.fileInfos.get(ts.tscWatch.libFile.path as ts.Path), {
|
||||
version: system.createHash(ts.tscWatch.libFile.content),
|
||||
signature: system.createHash(ts.tscWatch.libFile.content),
|
||||
assert.deepEqual(state.fileInfos.get(libFile.path as ts.Path), {
|
||||
version: system.createHash(libFile.content),
|
||||
signature: system.createHash(libFile.content),
|
||||
affectsGlobalScope: true,
|
||||
impliedFormat: undefined,
|
||||
});
|
||||
@@ -189,7 +192,7 @@ describe("unittests:: tsc-watch:: emit file --incremental", () => {
|
||||
assert.equal(ts.arrayFrom(state.exportedModulesMap!.keys()).length, 0);
|
||||
|
||||
assert.equal(state.semanticDiagnosticsPerFile!.size, 3);
|
||||
assert.deepEqual(state.semanticDiagnosticsPerFile!.get(ts.tscWatch.libFile.path as ts.Path), ts.emptyArray);
|
||||
assert.deepEqual(state.semanticDiagnosticsPerFile!.get(libFile.path as ts.Path), ts.emptyArray);
|
||||
assert.deepEqual(state.semanticDiagnosticsPerFile!.get(file1.path as ts.Path), ts.emptyArray);
|
||||
assert.deepEqual(state.semanticDiagnosticsPerFile!.get(file2.path as ts.Path), [{
|
||||
file: state.program!.getSourceFileByPath(file2.path as ts.Path)!,
|
||||
@@ -208,7 +211,7 @@ describe("unittests:: tsc-watch:: emit file --incremental", () => {
|
||||
});
|
||||
|
||||
verifyIncrementalWatchEmit({
|
||||
files: () => [ts.tscWatch.libFile, file1, file2, {
|
||||
files: () => [libFile, file1, file2, {
|
||||
path: configFile.path,
|
||||
content: JSON.stringify({ compilerOptions: { incremental: true, module: "amd", outFile: "out.js" } })
|
||||
}],
|
||||
@@ -218,7 +221,7 @@ describe("unittests:: tsc-watch:: emit file --incremental", () => {
|
||||
|
||||
verifyIncrementalWatchEmit({
|
||||
files: () => {
|
||||
const config: ts.tscWatch.File = {
|
||||
const config: File = {
|
||||
path: configFile.path,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
@@ -230,7 +233,7 @@ describe("unittests:: tsc-watch:: emit file --incremental", () => {
|
||||
}
|
||||
})
|
||||
};
|
||||
const aTs: ts.tscWatch.File = {
|
||||
const aTs: File = {
|
||||
path: `${project}/a.ts`,
|
||||
content: `import { B } from "./b";
|
||||
export interface A {
|
||||
@@ -238,7 +241,7 @@ export interface A {
|
||||
}
|
||||
`
|
||||
};
|
||||
const bTs: ts.tscWatch.File = {
|
||||
const bTs: File = {
|
||||
path: `${project}/b.ts`,
|
||||
content: `import { C } from "./c";
|
||||
export interface B {
|
||||
@@ -246,7 +249,7 @@ export interface B {
|
||||
}
|
||||
`
|
||||
};
|
||||
const cTs: ts.tscWatch.File = {
|
||||
const cTs: File = {
|
||||
path: `${project}/c.ts`,
|
||||
content: `import { A } from "./a";
|
||||
export interface C {
|
||||
@@ -254,14 +257,14 @@ export interface C {
|
||||
}
|
||||
`
|
||||
};
|
||||
const indexTs: ts.tscWatch.File = {
|
||||
const indexTs: File = {
|
||||
path: `${project}/index.ts`,
|
||||
content: `export { A } from "./a";
|
||||
export { B } from "./b";
|
||||
export { C } from "./c";
|
||||
`
|
||||
};
|
||||
return [ts.tscWatch.libFile, aTs, bTs, cTs, indexTs, config];
|
||||
return [libFile, aTs, bTs, cTs, indexTs, config];
|
||||
},
|
||||
subScenario: "incremental with circular references",
|
||||
modifyFs: host => host.writeFile(`${project}/a.ts`, `import { B } from "./b";
|
||||
@@ -275,7 +278,7 @@ export interface A {
|
||||
verifyIncrementalWatchEmit({
|
||||
subScenario: "when file with ambient global declaration file is deleted",
|
||||
files: () => [
|
||||
{ path: ts.tscWatch.libFile.path, content: ts.libContent },
|
||||
{ path: libFile.path, content: libContent },
|
||||
{ path: `${project}/globals.d.ts`, content: `declare namespace Config { const value: string;} ` },
|
||||
{ path: `${project}/index.ts`, content: `console.log(Config.value);` },
|
||||
{ path: configFile.path, content: JSON.stringify({ compilerOptions: { incremental: true, } }) }
|
||||
@@ -301,7 +304,7 @@ export const Fragment: unique symbol;
|
||||
verifyIncrementalWatchEmit({
|
||||
subScenario: "jsxImportSource option changed",
|
||||
files: () => [
|
||||
{ path: ts.tscWatch.libFile.path, content: ts.libContent },
|
||||
{ path: libFile.path, content: libContent },
|
||||
{ path: `${project}/node_modules/react/jsx-runtime/index.d.ts`, content: jsxLibraryContent },
|
||||
{ path: `${project}/node_modules/react/package.json`, content: JSON.stringify({ name: "react", version: "0.0.1" }) },
|
||||
{ path: `${project}/node_modules/preact/jsx-runtime/index.d.ts`, content: jsxLibraryContent.replace("propA", "propB") },
|
||||
@@ -316,7 +319,7 @@ export const Fragment: unique symbol;
|
||||
verifyIncrementalWatchEmit({
|
||||
subScenario: "jsxImportSource backing types added",
|
||||
files: () => [
|
||||
{ path: ts.tscWatch.libFile.path, content: ts.libContent },
|
||||
{ path: libFile.path, content: libContent },
|
||||
{ path: `${project}/index.tsx`, content: `export const App = () => <div propA={true}></div>;` },
|
||||
{ path: configFile.path, content: JSON.stringify({ compilerOptions: jsxImportSourceOptions }) }
|
||||
],
|
||||
@@ -332,7 +335,7 @@ export const Fragment: unique symbol;
|
||||
verifyIncrementalWatchEmit({
|
||||
subScenario: "jsxImportSource backing types removed",
|
||||
files: () => [
|
||||
{ path: ts.tscWatch.libFile.path, content: ts.libContent },
|
||||
{ path: libFile.path, content: libContent },
|
||||
{ path: `${project}/node_modules/react/jsx-runtime/index.d.ts`, content: jsxLibraryContent },
|
||||
{ path: `${project}/node_modules/react/package.json`, content: JSON.stringify({ name: "react", version: "0.0.1" }) },
|
||||
{ path: `${project}/index.tsx`, content: `export const App = () => <div propA={true}></div>;` },
|
||||
@@ -347,7 +350,7 @@ export const Fragment: unique symbol;
|
||||
verifyIncrementalWatchEmit({
|
||||
subScenario: "importHelpers backing types removed",
|
||||
files: () => [
|
||||
{ path: ts.tscWatch.libFile.path, content: ts.libContent },
|
||||
{ path: libFile.path, content: libContent },
|
||||
{ path: `${project}/node_modules/tslib/index.d.ts`, content: "export function __assign(...args: any[]): any;" },
|
||||
{ path: `${project}/node_modules/tslib/package.json`, content: JSON.stringify({ name: "tslib", version: "0.0.1" }) },
|
||||
{ path: `${project}/index.tsx`, content: `export const x = {...{}};` },
|
||||
@@ -364,7 +367,7 @@ export const Fragment: unique symbol;
|
||||
verifyIncrementalWatchEmit({
|
||||
subScenario: "editing module augmentation",
|
||||
files: () => [
|
||||
{ path: ts.tscWatch.libFile.path, content: ts.libContent },
|
||||
{ path: libFile.path, content: libContent },
|
||||
{ path: `${project}/node_modules/classnames/index.d.ts`, content: `export interface Result {} export default function classNames(): Result;` },
|
||||
{ path: `${project}/src/types/classnames.d.ts`, content: `export {}; declare module "classnames" { interface Result { foo } }` },
|
||||
{ path: `${project}/src/index.ts`, content: `import classNames from "classnames"; classNames().foo;` },
|
||||
@@ -377,14 +380,14 @@ export const Fragment: unique symbol;
|
||||
});
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "incremental",
|
||||
subScenario: "tsbuildinfo has error",
|
||||
sys: () => ts.tscWatch.createWatchedSystem({
|
||||
sys: () => createWatchedSystem({
|
||||
"/src/project/main.ts": "export const x = 10;",
|
||||
"/src/project/tsconfig.json": "{}",
|
||||
"/src/project/tsconfig.tsbuildinfo": "Some random string",
|
||||
[ts.tscWatch.libFile.path]: ts.tscWatch.libFile.content,
|
||||
[libFile.path]: libFile.content,
|
||||
}),
|
||||
commandLineArgs: ["--p", "src/project", "-i", "-w"],
|
||||
changes: ts.emptyArray
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as Utils from "../../_namespaces/Utils";
|
||||
import { createWatchedSystem, File, libFile } from "../virtualFileSystemWithWatch";
|
||||
import { verifyTscWatch } from "./helpers";
|
||||
|
||||
describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "moduleResolution",
|
||||
subScenario: `watches for changes to package-json main fields`,
|
||||
sys: () => ts.tscWatch.createWatchedSystem([
|
||||
sys: () => createWatchedSystem([
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/packages/pkg1/package.json`,
|
||||
path: `/user/username/projects/myproject/packages/pkg1/package.json`,
|
||||
content: JSON.stringify({
|
||||
name: "pkg1",
|
||||
version: "1.0.0",
|
||||
@@ -15,13 +17,13 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
})
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/packages/pkg1/index.ts`,
|
||||
path: `/user/username/projects/myproject/packages/pkg1/index.ts`,
|
||||
content: Utils.dedent`
|
||||
import type { TheNum } from 'pkg2'
|
||||
export const theNum: TheNum = 42;`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/packages/pkg1/tsconfig.json`,
|
||||
path: `/user/username/projects/myproject/packages/pkg1/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
outDir: "build",
|
||||
@@ -29,19 +31,19 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
})
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/packages/pkg2/build/const.d.ts`,
|
||||
path: `/user/username/projects/myproject/packages/pkg2/build/const.d.ts`,
|
||||
content: `export type TheNum = 42;`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/packages/pkg2/build/index.d.ts`,
|
||||
path: `/user/username/projects/myproject/packages/pkg2/build/index.d.ts`,
|
||||
content: `export type { TheNum } from './const.js';`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/packages/pkg2/build/other.d.ts`,
|
||||
path: `/user/username/projects/myproject/packages/pkg2/build/other.d.ts`,
|
||||
content: `export type TheStr = string;`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/packages/pkg2/package.json`,
|
||||
path: `/user/username/projects/myproject/packages/pkg2/package.json`,
|
||||
content: JSON.stringify({
|
||||
name: "pkg2",
|
||||
version: "1.0.0",
|
||||
@@ -49,16 +51,16 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
})
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/pkg2`,
|
||||
symLink: `${ts.tscWatch.projectRoot}/packages/pkg2`,
|
||||
path: `/user/username/projects/myproject/node_modules/pkg2`,
|
||||
symLink: `/user/username/projects/myproject/packages/pkg2`,
|
||||
},
|
||||
ts.tscWatch.libFile
|
||||
], { currentDirectory: ts.tscWatch.projectRoot }),
|
||||
libFile
|
||||
], { currentDirectory: "/user/username/projects/myproject" }),
|
||||
commandLineArgs: ["--project", "./packages/pkg1/tsconfig.json", "-w", "--traceResolution"],
|
||||
changes: [
|
||||
{
|
||||
caption: "reports import errors after change to package file",
|
||||
change: sys => ts.tscWatch.replaceFileText(sys, `${ts.tscWatch.projectRoot}/packages/pkg2/package.json`, `index.js`, `other.js`),
|
||||
change: sys => sys.replaceFileText(`/user/username/projects/myproject/packages/pkg2/package.json`, `index.js`, `other.js`),
|
||||
timeouts: sys => {
|
||||
sys.runQueuedTimeoutCallbacks(); // invalidates failed lookups
|
||||
sys.runQueuedTimeoutCallbacks(); // actual update
|
||||
@@ -66,7 +68,7 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
},
|
||||
{
|
||||
caption: "removes those errors when a package file is changed back",
|
||||
change: sys => ts.tscWatch.replaceFileText(sys, `${ts.tscWatch.projectRoot}/packages/pkg2/package.json`, `other.js`, `index.js`),
|
||||
change: sys => sys.replaceFileText(`/user/username/projects/myproject/packages/pkg2/package.json`, `other.js`, `index.js`),
|
||||
timeouts: sys => {
|
||||
sys.runQueuedTimeoutCallbacks(); // invalidates failed lookups
|
||||
sys.runQueuedTimeoutCallbacks(); // actual update
|
||||
@@ -75,12 +77,12 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
]
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "moduleResolution",
|
||||
subScenario: "diagnostics from cache",
|
||||
sys: () => ts.tscWatch.createWatchedSystem([
|
||||
sys: () => createWatchedSystem([
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
moduleResolution: "nodenext",
|
||||
@@ -91,7 +93,7 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
})
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/package.json`,
|
||||
path: `/user/username/projects/myproject/package.json`,
|
||||
content: JSON.stringify({
|
||||
name: "@this/package",
|
||||
type: "module",
|
||||
@@ -104,23 +106,23 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
})
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/index.ts`,
|
||||
path: `/user/username/projects/myproject/index.ts`,
|
||||
content: Utils.dedent`
|
||||
import * as me from "@this/package";
|
||||
me.thing()
|
||||
export function thing(): void {}
|
||||
`
|
||||
},
|
||||
ts.tscWatch.libFile
|
||||
], { currentDirectory: ts.tscWatch.projectRoot }),
|
||||
libFile
|
||||
], { currentDirectory: "/user/username/projects/myproject" }),
|
||||
commandLineArgs: ["-w", "--traceResolution"],
|
||||
changes: ts.emptyArray
|
||||
});
|
||||
|
||||
describe("package json file is edited", () => {
|
||||
function getSys(packageFileContents: string) {
|
||||
const configFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/src/tsconfig.json`,
|
||||
const configFile: File = {
|
||||
path: `/user/username/projects/myproject/src/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
target: "es2016",
|
||||
@@ -129,30 +131,30 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
}
|
||||
})
|
||||
};
|
||||
const packageFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/package.json`,
|
||||
const packageFile: File = {
|
||||
path: `/user/username/projects/myproject/package.json`,
|
||||
content: packageFileContents
|
||||
};
|
||||
const fileA: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/src/fileA.ts`,
|
||||
const fileA: File = {
|
||||
path: `/user/username/projects/myproject/src/fileA.ts`,
|
||||
content: Utils.dedent`
|
||||
import { foo } from "./fileB.mjs";
|
||||
foo();
|
||||
`
|
||||
};
|
||||
const fileB: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/project/src/fileB.mts`,
|
||||
const fileB: File = {
|
||||
path: `/user/username/projects/myproject/project/src/fileB.mts`,
|
||||
content: Utils.dedent`
|
||||
export function foo() {
|
||||
}
|
||||
`
|
||||
};
|
||||
return ts.tscWatch.createWatchedSystem(
|
||||
[configFile, fileA, fileB, packageFile, { ...ts.tscWatch.libFile, path: "/a/lib/lib.es2016.full.d.ts" }],
|
||||
{ currentDirectory: ts.tscWatch.projectRoot }
|
||||
return createWatchedSystem(
|
||||
[configFile, fileA, fileB, packageFile, { ...libFile, path: "/a/lib/lib.es2016.full.d.ts" }],
|
||||
{ currentDirectory: "/user/username/projects/myproject" }
|
||||
);
|
||||
}
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "moduleResolution",
|
||||
subScenario: "package json file is edited",
|
||||
commandLineArgs: ["--w", "--p", "src", "--extendedDiagnostics", "-traceResolution", "--explainFiles"],
|
||||
@@ -160,7 +162,7 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
changes: [
|
||||
{
|
||||
caption: "Modify package json file to add type module",
|
||||
change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/package.json`, JSON.stringify({
|
||||
change: sys => sys.writeFile(`/user/username/projects/myproject/package.json`, JSON.stringify({
|
||||
name: "app", version: "1.0.0", type: "module",
|
||||
})),
|
||||
timeouts: host => {
|
||||
@@ -170,7 +172,7 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
},
|
||||
{
|
||||
caption: "Modify package.json file to remove type module",
|
||||
change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/package.json`, JSON.stringify({ name: "app", version: "1.0.0" })),
|
||||
change: sys => sys.writeFile(`/user/username/projects/myproject/package.json`, JSON.stringify({ name: "app", version: "1.0.0" })),
|
||||
timeouts: host => {
|
||||
host.runQueuedTimeoutCallbacks(); // Failed lookup updates
|
||||
host.runQueuedTimeoutCallbacks(); // Actual update
|
||||
@@ -178,7 +180,7 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
},
|
||||
{
|
||||
caption: "Delete package.json",
|
||||
change: sys => sys.deleteFile(`${ts.tscWatch.projectRoot}/package.json`),
|
||||
change: sys => sys.deleteFile(`/user/username/projects/myproject/package.json`),
|
||||
timeouts: host => {
|
||||
host.runQueuedTimeoutCallbacks(); // Failed lookup updates
|
||||
host.runQueuedTimeoutCallbacks(); // Actual update
|
||||
@@ -186,7 +188,7 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
},
|
||||
{
|
||||
caption: "Modify package json file to add type module",
|
||||
change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/package.json`, JSON.stringify({
|
||||
change: sys => sys.writeFile(`/user/username/projects/myproject/package.json`, JSON.stringify({
|
||||
name: "app", version: "1.0.0", type: "module",
|
||||
})),
|
||||
timeouts: host => {
|
||||
@@ -196,7 +198,7 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
},
|
||||
{
|
||||
caption: "Delete package.json",
|
||||
change: sys => sys.deleteFile(`${ts.tscWatch.projectRoot}/package.json`),
|
||||
change: sys => sys.deleteFile(`/user/username/projects/myproject/package.json`),
|
||||
timeouts: host => {
|
||||
host.runQueuedTimeoutCallbacks(); // Failed lookup updates
|
||||
host.runQueuedTimeoutCallbacks(); // Actual update
|
||||
@@ -205,7 +207,7 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
],
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "moduleResolution",
|
||||
subScenario: "package json file is edited when package json with type module exists",
|
||||
commandLineArgs: ["--w", "--p", "src", "--extendedDiagnostics", "-traceResolution", "--explainFiles"],
|
||||
@@ -215,7 +217,7 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
changes: [
|
||||
{
|
||||
caption: "Modify package.json file to remove type module",
|
||||
change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/package.json`, JSON.stringify({ name: "app", version: "1.0.0" })),
|
||||
change: sys => sys.writeFile(`/user/username/projects/myproject/package.json`, JSON.stringify({ name: "app", version: "1.0.0" })),
|
||||
timeouts: host => {
|
||||
host.runQueuedTimeoutCallbacks(); // Failed lookup updates
|
||||
host.runQueuedTimeoutCallbacks(); // Actual update
|
||||
@@ -223,7 +225,7 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
},
|
||||
{
|
||||
caption: "Modify package json file to add type module",
|
||||
change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/package.json`, JSON.stringify({
|
||||
change: sys => sys.writeFile(`/user/username/projects/myproject/package.json`, JSON.stringify({
|
||||
name: "app", version: "1.0.0", type: "module",
|
||||
})),
|
||||
timeouts: host => {
|
||||
@@ -233,7 +235,7 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
},
|
||||
{
|
||||
caption: "Delete package.json",
|
||||
change: sys => sys.deleteFile(`${ts.tscWatch.projectRoot}/package.json`),
|
||||
change: sys => sys.deleteFile(`/user/username/projects/myproject/package.json`),
|
||||
timeouts: host => {
|
||||
host.runQueuedTimeoutCallbacks(); // Failed lookup updates
|
||||
host.runQueuedTimeoutCallbacks(); // Actual update
|
||||
@@ -241,7 +243,7 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
},
|
||||
{
|
||||
caption: "Modify package json file to without type module",
|
||||
change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/package.json`, JSON.stringify({ name: "app", version: "1.0.0" })),
|
||||
change: sys => sys.writeFile(`/user/username/projects/myproject/package.json`, JSON.stringify({ name: "app", version: "1.0.0" })),
|
||||
timeouts: host => {
|
||||
host.runQueuedTimeoutCallbacks(); // Failed lookup updates
|
||||
host.runQueuedTimeoutCallbacks(); // Actual update
|
||||
@@ -249,7 +251,7 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
},
|
||||
{
|
||||
caption: "Delete package.json",
|
||||
change: sys => sys.deleteFile(`${ts.tscWatch.projectRoot}/package.json`),
|
||||
change: sys => sys.deleteFile(`/user/username/projects/myproject/package.json`),
|
||||
timeouts: host => {
|
||||
host.runQueuedTimeoutCallbacks(); // Failed lookup updates
|
||||
host.runQueuedTimeoutCallbacks(); // Actual update
|
||||
@@ -259,18 +261,18 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
});
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "moduleResolution",
|
||||
subScenario: "module resolutions from file are partially used",
|
||||
sys: () => ts.tscWatch.createWatchedSystem([
|
||||
sys: () => createWatchedSystem([
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { moduleResolution: "node16" },
|
||||
})
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/index.ts`,
|
||||
path: `/user/username/projects/myproject/index.ts`,
|
||||
content: Utils.dedent`
|
||||
import type { ImportInterface } from "pkg" assert { "resolution-mode": "import" };
|
||||
import type { RequireInterface } from "pkg1" assert { "resolution-mode": "require" };
|
||||
@@ -278,13 +280,13 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/a.ts`,
|
||||
path: `/user/username/projects/myproject/a.ts`,
|
||||
content: Utils.dedent`
|
||||
export const x = 10;
|
||||
`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/pkg/package.json`,
|
||||
path: `/user/username/projects/myproject/node_modules/pkg/package.json`,
|
||||
content: JSON.stringify({
|
||||
name: "pkg",
|
||||
version: "0.0.1",
|
||||
@@ -295,15 +297,15 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
})
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/pkg/import.d.ts`,
|
||||
path: `/user/username/projects/myproject/node_modules/pkg/import.d.ts`,
|
||||
content: `export interface ImportInterface {}`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/pkg/require.d.ts`,
|
||||
path: `/user/username/projects/myproject/node_modules/pkg/require.d.ts`,
|
||||
content: `export interface RequireInterface {}`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/pkg1/package.json`,
|
||||
path: `/user/username/projects/myproject/node_modules/pkg1/package.json`,
|
||||
content: JSON.stringify({
|
||||
name: "pkg1",
|
||||
version: "0.0.1",
|
||||
@@ -314,33 +316,33 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
})
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/pkg1/import.d.ts`,
|
||||
path: `/user/username/projects/myproject/node_modules/pkg1/import.d.ts`,
|
||||
content: `export interface ImportInterface {}`
|
||||
},
|
||||
ts.tscWatch.libFile
|
||||
], { currentDirectory: ts.tscWatch.projectRoot }),
|
||||
libFile
|
||||
], { currentDirectory: "/user/username/projects/myproject" }),
|
||||
commandLineArgs: ["-w", "--traceResolution"],
|
||||
changes: [
|
||||
{
|
||||
caption: "modify aFile by adding import",
|
||||
change: sys => sys.appendFile(`${ts.tscWatch.projectRoot}/a.ts`, `import type { ImportInterface } from "pkg" assert { "resolution-mode": "import" }`),
|
||||
change: sys => sys.appendFile(`/user/username/projects/myproject/a.ts`, `import type { ImportInterface } from "pkg" assert { "resolution-mode": "import" }`),
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "moduleResolution",
|
||||
subScenario: "type reference resolutions reuse",
|
||||
sys: () => ts.tscWatch.createWatchedSystem([
|
||||
sys: () => createWatchedSystem([
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { moduleResolution: "node16" },
|
||||
})
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/index.ts`,
|
||||
path: `/user/username/projects/myproject/index.ts`,
|
||||
content: Utils.dedent`
|
||||
/// <reference types="pkg" resolution-mode="import"/>
|
||||
/// <reference types="pkg1" resolution-mode="require"/>
|
||||
@@ -348,13 +350,13 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/a.ts`,
|
||||
path: `/user/username/projects/myproject/a.ts`,
|
||||
content: Utils.dedent`
|
||||
export const x = 10;
|
||||
`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/pkg/package.json`,
|
||||
path: `/user/username/projects/myproject/node_modules/pkg/package.json`,
|
||||
content: JSON.stringify({
|
||||
name: "pkg",
|
||||
version: "0.0.1",
|
||||
@@ -365,7 +367,7 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
})
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/pkg/import.d.ts`,
|
||||
path: `/user/username/projects/myproject/node_modules/pkg/import.d.ts`,
|
||||
content: Utils.dedent`
|
||||
export {};
|
||||
declare global {
|
||||
@@ -374,7 +376,7 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/pkg/require.d.ts`,
|
||||
path: `/user/username/projects/myproject/node_modules/pkg/require.d.ts`,
|
||||
content: Utils.dedent`
|
||||
export {};
|
||||
declare global {
|
||||
@@ -383,7 +385,7 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/pkg1/package.json`,
|
||||
path: `/user/username/projects/myproject/node_modules/pkg1/package.json`,
|
||||
content: JSON.stringify({
|
||||
name: "pkg1",
|
||||
version: "0.0.1",
|
||||
@@ -394,7 +396,7 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
})
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/pkg1/import.d.ts`,
|
||||
path: `/user/username/projects/myproject/node_modules/pkg1/import.d.ts`,
|
||||
content: Utils.dedent`
|
||||
export {};
|
||||
declare global {
|
||||
@@ -403,16 +405,16 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
`
|
||||
},
|
||||
{
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/@types/pkg2/index.d.ts`,
|
||||
path: `/user/username/projects/myproject/node_modules/@types/pkg2/index.d.ts`,
|
||||
content: `export const x = 10;`
|
||||
},
|
||||
ts.tscWatch.libFile
|
||||
], { currentDirectory: ts.tscWatch.projectRoot }),
|
||||
libFile
|
||||
], { currentDirectory: "/user/username/projects/myproject" }),
|
||||
commandLineArgs: ["-w", "--traceResolution"],
|
||||
changes: [
|
||||
{
|
||||
caption: "modify aFile by adding import",
|
||||
change: sys => sys.prependFile(`${ts.tscWatch.projectRoot}/a.ts`, `/// <reference types="pkg" resolution-mode="import"/>\n`),
|
||||
change: sys => sys.prependFile(`/user/username/projects/myproject/a.ts`, `/// <reference types="pkg" resolution-mode="import"/>\n`),
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as Utils from "../../_namespaces/Utils";
|
||||
import { createWatchedSystem, File, libFile } from "../virtualFileSystemWithWatch";
|
||||
import { verifyTscWatch } from "./helpers";
|
||||
|
||||
describe("unittests:: tsc-watch:: nodeNextWatch:: emit when module emit is specified as nodenext", () => {
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "nodenext watch emit",
|
||||
subScenario: "esm-mode file is edited",
|
||||
commandLineArgs: ["--w", "--p", "/project/tsconfig.json"],
|
||||
sys: () => {
|
||||
const configFile: ts.tscWatch.File = {
|
||||
const configFile: File = {
|
||||
path: "/project/tsconfig.json",
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
@@ -19,7 +20,7 @@ describe("unittests:: tsc-watch:: nodeNextWatch:: emit when module emit is speci
|
||||
}
|
||||
})
|
||||
};
|
||||
const packageFile: ts.tscWatch.File = {
|
||||
const packageFile: File = {
|
||||
path: "/project/package.json",
|
||||
content: JSON.stringify({
|
||||
name: "some-proj",
|
||||
@@ -29,18 +30,18 @@ describe("unittests:: tsc-watch:: nodeNextWatch:: emit when module emit is speci
|
||||
main: "index.js",
|
||||
})
|
||||
};
|
||||
const file1: ts.tscWatch.File = {
|
||||
const file1: File = {
|
||||
path: "/project/src/index.ts",
|
||||
content: Utils.dedent`
|
||||
import * as Thing from "thing";
|
||||
|
||||
Thing.fn();`
|
||||
};
|
||||
const declFile: ts.tscWatch.File = {
|
||||
const declFile: File = {
|
||||
path: "/project/src/deps.d.ts",
|
||||
content: `declare module "thing";`
|
||||
};
|
||||
return ts.tscWatch.createWatchedSystem([configFile, file1, declFile, packageFile, { ...ts.tscWatch.libFile, path: "/a/lib/lib.es2020.full.d.ts" }]);
|
||||
return createWatchedSystem([configFile, file1, declFile, packageFile, { ...libFile, path: "/a/lib/lib.es2020.full.d.ts" }]);
|
||||
},
|
||||
changes: [
|
||||
{
|
||||
@@ -52,7 +53,7 @@ describe("unittests:: tsc-watch:: nodeNextWatch:: emit when module emit is speci
|
||||
Thing.fn();`,
|
||||
{},
|
||||
),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks,
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,31 +1,33 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { getTsBuildProjectFile, getTsBuildProjectFilePath, libFile, TestServerHost } from "../virtualFileSystemWithWatch";
|
||||
import { createSolutionBuilder, createSystemWithSolutionBuild, verifyTscWatch } from "./helpers";
|
||||
|
||||
describe("unittests:: tsc-watch:: projects with references: invoking when references are already built", () => {
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "projectsWithReferences",
|
||||
subScenario: "on sample project",
|
||||
sys: () => ts.tscWatch.createSystemWithSolutionBuild(
|
||||
sys: () => createSystemWithSolutionBuild(
|
||||
["tests"],
|
||||
[
|
||||
ts.tscWatch.libFile,
|
||||
ts.TestFSWithWatch.getTsBuildProjectFile("sample1", "core/tsconfig.json"),
|
||||
ts.TestFSWithWatch.getTsBuildProjectFile("sample1", "core/index.ts"),
|
||||
ts.TestFSWithWatch.getTsBuildProjectFile("sample1", "core/anotherModule.ts"),
|
||||
ts.TestFSWithWatch.getTsBuildProjectFile("sample1", "core/some_decl.d.ts"),
|
||||
ts.TestFSWithWatch.getTsBuildProjectFile("sample1", "logic/tsconfig.json"),
|
||||
ts.TestFSWithWatch.getTsBuildProjectFile("sample1", "logic/index.ts"),
|
||||
ts.TestFSWithWatch.getTsBuildProjectFile("sample1", "tests/tsconfig.json"),
|
||||
ts.TestFSWithWatch.getTsBuildProjectFile("sample1", "tests/index.ts"),
|
||||
libFile,
|
||||
getTsBuildProjectFile("sample1", "core/tsconfig.json"),
|
||||
getTsBuildProjectFile("sample1", "core/index.ts"),
|
||||
getTsBuildProjectFile("sample1", "core/anotherModule.ts"),
|
||||
getTsBuildProjectFile("sample1", "core/some_decl.d.ts"),
|
||||
getTsBuildProjectFile("sample1", "logic/tsconfig.json"),
|
||||
getTsBuildProjectFile("sample1", "logic/index.ts"),
|
||||
getTsBuildProjectFile("sample1", "tests/tsconfig.json"),
|
||||
getTsBuildProjectFile("sample1", "tests/index.ts"),
|
||||
],
|
||||
{ currentDirectory: `${ts.TestFSWithWatch.tsbuildProjectsLocation}/sample1` }
|
||||
{ currentDirectory: `/user/username/projects/sample1` }
|
||||
),
|
||||
commandLineArgs: ["-w", "-p", "tests"],
|
||||
changes: [
|
||||
{
|
||||
caption: "local edit in logic ts, and build logic",
|
||||
change: sys => {
|
||||
sys.appendFile(ts.TestFSWithWatch.getTsBuildProjectFilePath("sample1", "logic/index.ts"), `function foo() { }`);
|
||||
const solutionBuilder = ts.tscWatch.createSolutionBuilder(sys, ["logic"]);
|
||||
sys.appendFile(getTsBuildProjectFilePath("sample1", "logic/index.ts"), `function foo() { }`);
|
||||
const solutionBuilder = createSolutionBuilder(sys, ["logic"]);
|
||||
solutionBuilder.build();
|
||||
},
|
||||
// not ideal, but currently because of d.ts but no new file is written
|
||||
@@ -35,160 +37,160 @@ describe("unittests:: tsc-watch:: projects with references: invoking when refere
|
||||
{
|
||||
caption: "non local edit in logic ts, and build logic",
|
||||
change: sys => {
|
||||
sys.appendFile(ts.TestFSWithWatch.getTsBuildProjectFilePath("sample1", "logic/index.ts"), `export function gfoo() { }`);
|
||||
const solutionBuilder = ts.tscWatch.createSolutionBuilder(sys, ["logic"]);
|
||||
sys.appendFile(getTsBuildProjectFilePath("sample1", "logic/index.ts"), `export function gfoo() { }`);
|
||||
const solutionBuilder = createSolutionBuilder(sys, ["logic"]);
|
||||
solutionBuilder.build();
|
||||
},
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1)
|
||||
},
|
||||
{
|
||||
caption: "change in project reference config file builds correctly",
|
||||
change: sys => {
|
||||
sys.writeFile(ts.TestFSWithWatch.getTsBuildProjectFilePath("sample1", "logic/tsconfig.json"), JSON.stringify({
|
||||
sys.writeFile(getTsBuildProjectFilePath("sample1", "logic/tsconfig.json"), JSON.stringify({
|
||||
compilerOptions: { composite: true, declaration: true, declarationDir: "decls" },
|
||||
references: [{ path: "../core" }]
|
||||
}));
|
||||
const solutionBuilder = ts.tscWatch.createSolutionBuilder(sys, ["logic"]);
|
||||
const solutionBuilder = createSolutionBuilder(sys, ["logic"]);
|
||||
solutionBuilder.build();
|
||||
},
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1)
|
||||
},
|
||||
],
|
||||
baselineDependencies: true
|
||||
});
|
||||
|
||||
function changeCompilerOpitonsPaths(sys: ts.tscWatch.WatchedSystem, config: string, newPaths: object) {
|
||||
function changeCompilerOpitonsPaths(sys: TestServerHost, config: string, newPaths: object) {
|
||||
const configJson = JSON.parse(sys.readFile(config)!);
|
||||
configJson.compilerOptions.paths = newPaths;
|
||||
sys.writeFile(config, JSON.stringify(configJson));
|
||||
}
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "projectsWithReferences",
|
||||
subScenario: "on transitive references",
|
||||
sys: () => ts.tscWatch.createSystemWithSolutionBuild(
|
||||
sys: () => createSystemWithSolutionBuild(
|
||||
["tsconfig.c.json"],
|
||||
[
|
||||
ts.tscWatch.libFile,
|
||||
ts.TestFSWithWatch.getTsBuildProjectFile("transitiveReferences", "tsconfig.a.json"),
|
||||
ts.TestFSWithWatch.getTsBuildProjectFile("transitiveReferences", "tsconfig.b.json"),
|
||||
ts.TestFSWithWatch.getTsBuildProjectFile("transitiveReferences", "tsconfig.c.json"),
|
||||
ts.TestFSWithWatch.getTsBuildProjectFile("transitiveReferences", "a.ts"),
|
||||
ts.TestFSWithWatch.getTsBuildProjectFile("transitiveReferences", "b.ts"),
|
||||
ts.TestFSWithWatch.getTsBuildProjectFile("transitiveReferences", "c.ts"),
|
||||
ts.TestFSWithWatch.getTsBuildProjectFile("transitiveReferences", "refs/a.d.ts"),
|
||||
libFile,
|
||||
getTsBuildProjectFile("transitiveReferences", "tsconfig.a.json"),
|
||||
getTsBuildProjectFile("transitiveReferences", "tsconfig.b.json"),
|
||||
getTsBuildProjectFile("transitiveReferences", "tsconfig.c.json"),
|
||||
getTsBuildProjectFile("transitiveReferences", "a.ts"),
|
||||
getTsBuildProjectFile("transitiveReferences", "b.ts"),
|
||||
getTsBuildProjectFile("transitiveReferences", "c.ts"),
|
||||
getTsBuildProjectFile("transitiveReferences", "refs/a.d.ts"),
|
||||
],
|
||||
{ currentDirectory: `${ts.TestFSWithWatch.tsbuildProjectsLocation}/transitiveReferences` }
|
||||
{ currentDirectory: `/user/username/projects/transitiveReferences` }
|
||||
),
|
||||
commandLineArgs: ["-w", "-p", "tsconfig.c.json"],
|
||||
changes: [
|
||||
{
|
||||
caption: "non local edit b ts, and build b",
|
||||
change: sys => {
|
||||
sys.appendFile(ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b.ts"), `export function gfoo() { }`);
|
||||
const solutionBuilder = ts.tscWatch.createSolutionBuilder(sys, ["tsconfig.b.json"]);
|
||||
sys.appendFile(getTsBuildProjectFilePath("transitiveReferences", "b.ts"), `export function gfoo() { }`);
|
||||
const solutionBuilder = createSolutionBuilder(sys, ["tsconfig.b.json"]);
|
||||
solutionBuilder.build();
|
||||
},
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1)
|
||||
},
|
||||
{
|
||||
caption: "edit on config file",
|
||||
change: sys => {
|
||||
sys.ensureFileOrFolder({
|
||||
path: ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "nrefs/a.d.ts"),
|
||||
content: sys.readFile(ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "refs/a.d.ts"))!
|
||||
path: getTsBuildProjectFilePath("transitiveReferences", "nrefs/a.d.ts"),
|
||||
content: sys.readFile(getTsBuildProjectFilePath("transitiveReferences", "refs/a.d.ts"))!
|
||||
});
|
||||
changeCompilerOpitonsPaths(sys, ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "tsconfig.c.json"), { "@ref/*": ["./nrefs/*"] });
|
||||
changeCompilerOpitonsPaths(sys, getTsBuildProjectFilePath("transitiveReferences", "tsconfig.c.json"), { "@ref/*": ["./nrefs/*"] });
|
||||
},
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1)
|
||||
},
|
||||
{
|
||||
caption: "Revert config file edit",
|
||||
change: sys => changeCompilerOpitonsPaths(sys, ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "tsconfig.c.json"), { "@ref/*": ["./refs/*"] }),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun
|
||||
change: sys => changeCompilerOpitonsPaths(sys, getTsBuildProjectFilePath("transitiveReferences", "tsconfig.c.json"), { "@ref/*": ["./refs/*"] }),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1)
|
||||
},
|
||||
{
|
||||
caption: "edit in referenced config file",
|
||||
change: sys => changeCompilerOpitonsPaths(sys, ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "tsconfig.b.json"), { "@ref/*": ["./nrefs/*"] }),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun
|
||||
change: sys => changeCompilerOpitonsPaths(sys, getTsBuildProjectFilePath("transitiveReferences", "tsconfig.b.json"), { "@ref/*": ["./nrefs/*"] }),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1)
|
||||
},
|
||||
{
|
||||
caption: "Revert referenced config file edit",
|
||||
change: sys => changeCompilerOpitonsPaths(sys, ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "tsconfig.b.json"), { "@ref/*": ["./refs/*"] }),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun
|
||||
change: sys => changeCompilerOpitonsPaths(sys, getTsBuildProjectFilePath("transitiveReferences", "tsconfig.b.json"), { "@ref/*": ["./refs/*"] }),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1)
|
||||
},
|
||||
{
|
||||
caption: "deleting referenced config file",
|
||||
change: sys => sys.deleteFile(ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "tsconfig.b.json")),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun
|
||||
change: sys => sys.deleteFile(getTsBuildProjectFilePath("transitiveReferences", "tsconfig.b.json")),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1)
|
||||
},
|
||||
{
|
||||
caption: "Revert deleting referenced config file",
|
||||
change: sys => sys.ensureFileOrFolder(ts.TestFSWithWatch.getTsBuildProjectFile("transitiveReferences", "tsconfig.b.json")),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun
|
||||
change: sys => sys.ensureFileOrFolder(getTsBuildProjectFile("transitiveReferences", "tsconfig.b.json")),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1)
|
||||
},
|
||||
{
|
||||
caption: "deleting transitively referenced config file",
|
||||
change: sys => sys.deleteFile(ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "tsconfig.a.json")),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun
|
||||
change: sys => sys.deleteFile(getTsBuildProjectFilePath("transitiveReferences", "tsconfig.a.json")),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1)
|
||||
},
|
||||
{
|
||||
caption: "Revert deleting transitively referenced config file",
|
||||
change: sys => sys.ensureFileOrFolder(ts.TestFSWithWatch.getTsBuildProjectFile("transitiveReferences", "tsconfig.a.json")),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun
|
||||
change: sys => sys.ensureFileOrFolder(getTsBuildProjectFile("transitiveReferences", "tsconfig.a.json")),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1)
|
||||
},
|
||||
],
|
||||
baselineDependencies: true,
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "projectsWithReferences",
|
||||
subScenario: "when referenced project uses different module resolution",
|
||||
sys: () => ts.tscWatch.createSystemWithSolutionBuild(
|
||||
sys: () => createSystemWithSolutionBuild(
|
||||
["tsconfig.c.json"],
|
||||
[
|
||||
ts.tscWatch.libFile,
|
||||
ts.TestFSWithWatch.getTsBuildProjectFile("transitiveReferences", "tsconfig.a.json"),
|
||||
libFile,
|
||||
getTsBuildProjectFile("transitiveReferences", "tsconfig.a.json"),
|
||||
{
|
||||
path: ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "tsconfig.b.json"),
|
||||
path: getTsBuildProjectFilePath("transitiveReferences", "tsconfig.b.json"),
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { composite: true, moduleResolution: "classic" },
|
||||
files: ["b.ts"],
|
||||
references: [{ path: "tsconfig.a.json" }]
|
||||
})
|
||||
},
|
||||
ts.TestFSWithWatch.getTsBuildProjectFile("transitiveReferences", "tsconfig.c.json"),
|
||||
ts.TestFSWithWatch.getTsBuildProjectFile("transitiveReferences", "a.ts"),
|
||||
getTsBuildProjectFile("transitiveReferences", "tsconfig.c.json"),
|
||||
getTsBuildProjectFile("transitiveReferences", "a.ts"),
|
||||
{
|
||||
path: ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b.ts"),
|
||||
path: getTsBuildProjectFilePath("transitiveReferences", "b.ts"),
|
||||
content: `import {A} from "a";export const b = new A();`
|
||||
},
|
||||
ts.TestFSWithWatch.getTsBuildProjectFile("transitiveReferences", "c.ts"),
|
||||
ts.TestFSWithWatch.getTsBuildProjectFile("transitiveReferences", "refs/a.d.ts"),
|
||||
getTsBuildProjectFile("transitiveReferences", "c.ts"),
|
||||
getTsBuildProjectFile("transitiveReferences", "refs/a.d.ts"),
|
||||
],
|
||||
{ currentDirectory: `${ts.TestFSWithWatch.tsbuildProjectsLocation}/transitiveReferences` }
|
||||
{ currentDirectory: `/user/username/projects/transitiveReferences` }
|
||||
),
|
||||
commandLineArgs: ["-w", "-p", "tsconfig.c.json"],
|
||||
changes: ts.emptyArray,
|
||||
baselineDependencies: true,
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "projectsWithReferences",
|
||||
subScenario: "on transitive references in different folders",
|
||||
sys: () => ts.tscWatch.createSystemWithSolutionBuild(
|
||||
sys: () => createSystemWithSolutionBuild(
|
||||
["c"],
|
||||
[
|
||||
ts.tscWatch.libFile,
|
||||
libFile,
|
||||
{
|
||||
path: ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "a/tsconfig.json"),
|
||||
path: getTsBuildProjectFilePath("transitiveReferences", "a/tsconfig.json"),
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { composite: true },
|
||||
files: ["index.ts"]
|
||||
}),
|
||||
},
|
||||
{
|
||||
path: ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"),
|
||||
path: getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"),
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { composite: true, baseUrl: "./", paths: { "@ref/*": ["../*"] } },
|
||||
files: ["index.ts"],
|
||||
@@ -196,7 +198,7 @@ describe("unittests:: tsc-watch:: projects with references: invoking when refere
|
||||
}),
|
||||
},
|
||||
{
|
||||
path: ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"),
|
||||
path: getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"),
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { baseUrl: "./", paths: { "@ref/*": ["../refs/*"] } },
|
||||
files: ["index.ts"],
|
||||
@@ -204,71 +206,71 @@ describe("unittests:: tsc-watch:: projects with references: invoking when refere
|
||||
}),
|
||||
},
|
||||
{
|
||||
path: ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "a/index.ts"),
|
||||
path: getTsBuildProjectFilePath("transitiveReferences", "a/index.ts"),
|
||||
content: `export class A {}`,
|
||||
},
|
||||
{
|
||||
path: ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/index.ts"),
|
||||
path: getTsBuildProjectFilePath("transitiveReferences", "b/index.ts"),
|
||||
content: `import {A} from '@ref/a';
|
||||
export const b = new A();`,
|
||||
},
|
||||
{
|
||||
path: ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "c/index.ts"),
|
||||
path: getTsBuildProjectFilePath("transitiveReferences", "c/index.ts"),
|
||||
content: `import {b} from '../b';
|
||||
import {X} from "@ref/a";
|
||||
b;
|
||||
X;`,
|
||||
},
|
||||
ts.TestFSWithWatch.getTsBuildProjectFile("transitiveReferences", "refs/a.d.ts"),
|
||||
getTsBuildProjectFile("transitiveReferences", "refs/a.d.ts"),
|
||||
],
|
||||
{ currentDirectory: `${ts.TestFSWithWatch.tsbuildProjectsLocation}/transitiveReferences` }
|
||||
{ currentDirectory: `/user/username/projects/transitiveReferences` }
|
||||
),
|
||||
commandLineArgs: ["-w", "-p", "c"],
|
||||
changes: [
|
||||
{
|
||||
caption: "non local edit b ts, and build b",
|
||||
change: sys => {
|
||||
sys.appendFile(ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/index.ts"), `export function gfoo() { }`);
|
||||
const solutionBuilder = ts.tscWatch.createSolutionBuilder(sys, ["b"]);
|
||||
sys.appendFile(getTsBuildProjectFilePath("transitiveReferences", "b/index.ts"), `export function gfoo() { }`);
|
||||
const solutionBuilder = createSolutionBuilder(sys, ["b"]);
|
||||
solutionBuilder.build();
|
||||
},
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1)
|
||||
},
|
||||
{
|
||||
caption: "edit on config file",
|
||||
change: sys => {
|
||||
sys.ensureFileOrFolder({
|
||||
path: ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "nrefs/a.d.ts"),
|
||||
content: sys.readFile(ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "refs/a.d.ts"))!
|
||||
path: getTsBuildProjectFilePath("transitiveReferences", "nrefs/a.d.ts"),
|
||||
content: sys.readFile(getTsBuildProjectFilePath("transitiveReferences", "refs/a.d.ts"))!
|
||||
});
|
||||
changeCompilerOpitonsPaths(sys, ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"), { "@ref/*": ["../nrefs/*"] });
|
||||
changeCompilerOpitonsPaths(sys, getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"), { "@ref/*": ["../nrefs/*"] });
|
||||
},
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1)
|
||||
},
|
||||
{
|
||||
caption: "Revert config file edit",
|
||||
change: sys => changeCompilerOpitonsPaths(sys, ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"), { "@ref/*": ["../refs/*"] }),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun
|
||||
change: sys => changeCompilerOpitonsPaths(sys, getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"), { "@ref/*": ["../refs/*"] }),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1)
|
||||
},
|
||||
{
|
||||
caption: "edit in referenced config file",
|
||||
change: sys => changeCompilerOpitonsPaths(sys, ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), { "@ref/*": ["../nrefs/*"] }),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun
|
||||
change: sys => changeCompilerOpitonsPaths(sys, getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), { "@ref/*": ["../nrefs/*"] }),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1)
|
||||
},
|
||||
{
|
||||
caption: "Revert referenced config file edit",
|
||||
change: sys => changeCompilerOpitonsPaths(sys, ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), { "@ref/*": ["../refs/*"] }),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun
|
||||
change: sys => changeCompilerOpitonsPaths(sys, getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), { "@ref/*": ["../refs/*"] }),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1)
|
||||
},
|
||||
{
|
||||
caption: "deleting referenced config file",
|
||||
change: sys => sys.deleteFile(ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json")),
|
||||
change: sys => sys.deleteFile(getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json")),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(2)
|
||||
},
|
||||
{
|
||||
caption: "Revert deleting referenced config file",
|
||||
change: sys => sys.writeFile(
|
||||
ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"),
|
||||
getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"),
|
||||
JSON.stringify({
|
||||
compilerOptions: { composite: true, baseUrl: "./", paths: { "@ref/*": ["../*"] } },
|
||||
files: ["index.ts"],
|
||||
@@ -279,13 +281,13 @@ X;`,
|
||||
},
|
||||
{
|
||||
caption: "deleting transitively referenced config file",
|
||||
change: sys => sys.deleteFile(ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "a/tsconfig.json")),
|
||||
change: sys => sys.deleteFile(getTsBuildProjectFilePath("transitiveReferences", "a/tsconfig.json")),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(2)
|
||||
},
|
||||
{
|
||||
caption: "Revert deleting transitively referenced config file",
|
||||
change: sys => sys.writeFile(
|
||||
ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "a/tsconfig.json"),
|
||||
getTsBuildProjectFilePath("transitiveReferences", "a/tsconfig.json"),
|
||||
JSON.stringify({
|
||||
compilerOptions: { composite: true },
|
||||
files: ["index.ts"]
|
||||
@@ -297,97 +299,97 @@ X;`,
|
||||
baselineDependencies: true,
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "projectsWithReferences",
|
||||
subScenario: "on transitive references in different folders with no files clause",
|
||||
sys: () => ts.tscWatch.createSystemWithSolutionBuild(
|
||||
sys: () => createSystemWithSolutionBuild(
|
||||
["c"],
|
||||
[
|
||||
ts.tscWatch.libFile,
|
||||
libFile,
|
||||
{
|
||||
path: ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "a/tsconfig.json"),
|
||||
path: getTsBuildProjectFilePath("transitiveReferences", "a/tsconfig.json"),
|
||||
content: JSON.stringify({ compilerOptions: { composite: true } }),
|
||||
},
|
||||
{
|
||||
path: ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"),
|
||||
path: getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"),
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { composite: true, baseUrl: "./", paths: { "@ref/*": ["../*"] } },
|
||||
references: [{ path: `../a` }]
|
||||
}),
|
||||
},
|
||||
{
|
||||
path: ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"),
|
||||
path: getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"),
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { baseUrl: "./", paths: { "@ref/*": ["../refs/*"] } },
|
||||
references: [{ path: `../b` }]
|
||||
}),
|
||||
},
|
||||
{
|
||||
path: ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "a/index.ts"),
|
||||
path: getTsBuildProjectFilePath("transitiveReferences", "a/index.ts"),
|
||||
content: `export class A {}`,
|
||||
},
|
||||
{
|
||||
path: ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/index.ts"),
|
||||
path: getTsBuildProjectFilePath("transitiveReferences", "b/index.ts"),
|
||||
content: `import {A} from '@ref/a';
|
||||
export const b = new A();`,
|
||||
},
|
||||
{
|
||||
path: ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "c/index.ts"),
|
||||
path: getTsBuildProjectFilePath("transitiveReferences", "c/index.ts"),
|
||||
content: `import {b} from '../b';
|
||||
import {X} from "@ref/a";
|
||||
b;
|
||||
X;`,
|
||||
},
|
||||
ts.TestFSWithWatch.getTsBuildProjectFile("transitiveReferences", "refs/a.d.ts"),
|
||||
getTsBuildProjectFile("transitiveReferences", "refs/a.d.ts"),
|
||||
],
|
||||
{ currentDirectory: `${ts.TestFSWithWatch.tsbuildProjectsLocation}/transitiveReferences` }
|
||||
{ currentDirectory: `/user/username/projects/transitiveReferences` }
|
||||
),
|
||||
commandLineArgs: ["-w", "-p", "c"],
|
||||
changes: [
|
||||
{
|
||||
caption: "non local edit b ts, and build b",
|
||||
change: sys => {
|
||||
sys.appendFile(ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/index.ts"), `export function gfoo() { }`);
|
||||
const solutionBuilder = ts.tscWatch.createSolutionBuilder(sys, ["b"]);
|
||||
sys.appendFile(getTsBuildProjectFilePath("transitiveReferences", "b/index.ts"), `export function gfoo() { }`);
|
||||
const solutionBuilder = createSolutionBuilder(sys, ["b"]);
|
||||
solutionBuilder.build();
|
||||
},
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1)
|
||||
},
|
||||
{
|
||||
caption: "edit on config file",
|
||||
change: sys => {
|
||||
sys.ensureFileOrFolder({
|
||||
path: ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "nrefs/a.d.ts"),
|
||||
content: sys.readFile(ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "refs/a.d.ts"))!
|
||||
path: getTsBuildProjectFilePath("transitiveReferences", "nrefs/a.d.ts"),
|
||||
content: sys.readFile(getTsBuildProjectFilePath("transitiveReferences", "refs/a.d.ts"))!
|
||||
});
|
||||
changeCompilerOpitonsPaths(sys, ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"), { "@ref/*": ["../nrefs/*"] });
|
||||
changeCompilerOpitonsPaths(sys, getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"), { "@ref/*": ["../nrefs/*"] });
|
||||
},
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1)
|
||||
},
|
||||
{
|
||||
caption: "Revert config file edit",
|
||||
change: sys => changeCompilerOpitonsPaths(sys, ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"), { "@ref/*": ["../refs/*"] }),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun
|
||||
change: sys => changeCompilerOpitonsPaths(sys, getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"), { "@ref/*": ["../refs/*"] }),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1)
|
||||
},
|
||||
{
|
||||
caption: "edit in referenced config file",
|
||||
change: sys => changeCompilerOpitonsPaths(sys, ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), { "@ref/*": ["../nrefs/*"] }),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun
|
||||
change: sys => changeCompilerOpitonsPaths(sys, getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), { "@ref/*": ["../nrefs/*"] }),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1)
|
||||
},
|
||||
{
|
||||
caption: "Revert referenced config file edit",
|
||||
change: sys => changeCompilerOpitonsPaths(sys, ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), { "@ref/*": ["../refs/*"] }),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun
|
||||
change: sys => changeCompilerOpitonsPaths(sys, getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), { "@ref/*": ["../refs/*"] }),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1)
|
||||
},
|
||||
{
|
||||
caption: "deleting referenced config file",
|
||||
change: sys => sys.deleteFile(ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json")),
|
||||
change: sys => sys.deleteFile(getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json")),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(2)
|
||||
},
|
||||
{
|
||||
caption: "Revert deleting referenced config file",
|
||||
change: sys => sys.writeFile(
|
||||
ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"),
|
||||
getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"),
|
||||
JSON.stringify({
|
||||
compilerOptions: { composite: true, baseUrl: "./", paths: { "@ref/*": ["../*"] } },
|
||||
references: [{ path: `../a` }]
|
||||
@@ -397,13 +399,13 @@ X;`,
|
||||
},
|
||||
{
|
||||
caption: "deleting transitively referenced config file",
|
||||
change: sys => sys.deleteFile(ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "a/tsconfig.json")),
|
||||
change: sys => sys.deleteFile(getTsBuildProjectFilePath("transitiveReferences", "a/tsconfig.json")),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(2)
|
||||
},
|
||||
{
|
||||
caption: "Revert deleting transitively referenced config file",
|
||||
change: sys => sys.writeFile(
|
||||
ts.TestFSWithWatch.getTsBuildProjectFilePath("transitiveReferences", "a/tsconfig.json"),
|
||||
getTsBuildProjectFilePath("transitiveReferences", "a/tsconfig.json"),
|
||||
JSON.stringify({ compilerOptions: { composite: true } }),
|
||||
),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(2)
|
||||
@@ -412,29 +414,29 @@ X;`,
|
||||
baselineDependencies: true,
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario: "projectsWithReferences",
|
||||
subScenario: "when declarationMap changes for dependency",
|
||||
sys: () => ts.tscWatch.createSystemWithSolutionBuild(
|
||||
sys: () => createSystemWithSolutionBuild(
|
||||
["core"],
|
||||
[
|
||||
ts.tscWatch.libFile,
|
||||
ts.TestFSWithWatch.getTsBuildProjectFile("sample1", "core/tsconfig.json"),
|
||||
ts.TestFSWithWatch.getTsBuildProjectFile("sample1", "core/index.ts"),
|
||||
ts.TestFSWithWatch.getTsBuildProjectFile("sample1", "core/anotherModule.ts"),
|
||||
ts.TestFSWithWatch.getTsBuildProjectFile("sample1", "core/some_decl.d.ts"),
|
||||
ts.TestFSWithWatch.getTsBuildProjectFile("sample1", "logic/tsconfig.json"),
|
||||
ts.TestFSWithWatch.getTsBuildProjectFile("sample1", "logic/index.ts"),
|
||||
libFile,
|
||||
getTsBuildProjectFile("sample1", "core/tsconfig.json"),
|
||||
getTsBuildProjectFile("sample1", "core/index.ts"),
|
||||
getTsBuildProjectFile("sample1", "core/anotherModule.ts"),
|
||||
getTsBuildProjectFile("sample1", "core/some_decl.d.ts"),
|
||||
getTsBuildProjectFile("sample1", "logic/tsconfig.json"),
|
||||
getTsBuildProjectFile("sample1", "logic/index.ts"),
|
||||
],
|
||||
{ currentDirectory: `${ts.TestFSWithWatch.tsbuildProjectsLocation}/sample1` }
|
||||
{ currentDirectory: `/user/username/projects/sample1` }
|
||||
),
|
||||
commandLineArgs: ["-w", "-p", "logic"],
|
||||
changes: [
|
||||
{
|
||||
caption: "change declration map in core",
|
||||
change: sys => {
|
||||
ts.tscWatch.replaceFileText(sys, ts.TestFSWithWatch.getTsBuildProjectFilePath("sample1", "core/tsconfig.json"), `"declarationMap": true,`, `"declarationMap": false,`);
|
||||
const solutionBuilder = ts.tscWatch.createSolutionBuilder(sys, ["core"]);
|
||||
sys.replaceFileText(getTsBuildProjectFilePath("sample1", "core/tsconfig.json"), `"declarationMap": true,`, `"declarationMap": false,`);
|
||||
const solutionBuilder = createSolutionBuilder(sys, ["core"]);
|
||||
solutionBuilder.build();
|
||||
},
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(0),
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { createWatchedSystem, File, libFile, SymLink } from "../virtualFileSystemWithWatch";
|
||||
import { createBaseline, createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline, runWatchBaseline, verifyTscWatch } from "./helpers";
|
||||
|
||||
describe("unittests:: tsc-watch:: resolutionCache:: tsc-watch module resolution caching", () => {
|
||||
const scenario = "resolutionCache";
|
||||
@@ -12,8 +14,8 @@ describe("unittests:: tsc-watch:: resolutionCache:: tsc-watch module resolution
|
||||
content: `foo()`
|
||||
};
|
||||
|
||||
const { sys, baseline, oldSnap, cb, getPrograms } = ts.tscWatch.createBaseline(ts.tscWatch.createWatchedSystem([root, imported, ts.tscWatch.libFile]));
|
||||
const host = ts.tscWatch.createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline({
|
||||
const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem([root, imported, libFile]));
|
||||
const host = createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline({
|
||||
rootFiles: [root.path],
|
||||
system: sys,
|
||||
options: { module: ts.ModuleKind.AMD },
|
||||
@@ -23,7 +25,7 @@ describe("unittests:: tsc-watch:: resolutionCache:: tsc-watch module resolution
|
||||
const originalFileExists = host.fileExists;
|
||||
const watch = ts.createWatchProgram(host);
|
||||
let fileExistsIsCalled = false;
|
||||
ts.tscWatch.runWatchBaseline({
|
||||
runWatchBaseline({
|
||||
scenario: "resolutionCache",
|
||||
subScenario: "caching works",
|
||||
commandLineArgs: ["--w", root.path],
|
||||
@@ -40,7 +42,7 @@ describe("unittests:: tsc-watch:: resolutionCache:: tsc-watch module resolution
|
||||
sys.writeFile(root.path, `import {x} from "f1"
|
||||
var x: string = 1;`);
|
||||
},
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks()
|
||||
},
|
||||
{
|
||||
caption: "Resolves f2",
|
||||
@@ -95,8 +97,8 @@ describe("unittests:: tsc-watch:: resolutionCache:: tsc-watch module resolution
|
||||
content: `export const y = 1;`
|
||||
};
|
||||
|
||||
const { sys, baseline, oldSnap, cb, getPrograms } = ts.tscWatch.createBaseline(ts.tscWatch.createWatchedSystem([root, ts.tscWatch.libFile]));
|
||||
const host = ts.tscWatch.createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline({
|
||||
const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem([root, libFile]));
|
||||
const host = createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline({
|
||||
rootFiles: [root.path],
|
||||
system: sys,
|
||||
options: { module: ts.ModuleKind.AMD },
|
||||
@@ -118,7 +120,7 @@ describe("unittests:: tsc-watch:: resolutionCache:: tsc-watch module resolution
|
||||
|
||||
const watch = ts.createWatchProgram(host);
|
||||
assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called");
|
||||
ts.tscWatch.runWatchBaseline({
|
||||
runWatchBaseline({
|
||||
scenario: "resolutionCache",
|
||||
subScenario: "loads missing files from disk",
|
||||
commandLineArgs: ["--w", root.path],
|
||||
@@ -153,8 +155,8 @@ describe("unittests:: tsc-watch:: resolutionCache:: tsc-watch module resolution
|
||||
content: `export const y = 1;export const x = 10;`
|
||||
};
|
||||
|
||||
const { sys, baseline, oldSnap, cb, getPrograms } = ts.tscWatch.createBaseline(ts.tscWatch.createWatchedSystem([root, imported, ts.tscWatch.libFile]));
|
||||
const host = ts.tscWatch.createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline({
|
||||
const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem([root, imported, libFile]));
|
||||
const host = createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline({
|
||||
rootFiles: [root.path],
|
||||
system: sys,
|
||||
options: { module: ts.ModuleKind.AMD },
|
||||
@@ -174,7 +176,7 @@ describe("unittests:: tsc-watch:: resolutionCache:: tsc-watch module resolution
|
||||
};
|
||||
const watch = ts.createWatchProgram(host);
|
||||
assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called");
|
||||
ts.tscWatch.runWatchBaseline({
|
||||
runWatchBaseline({
|
||||
scenario: "resolutionCache",
|
||||
subScenario: "should compile correctly when resolved module goes missing and then comes back",
|
||||
commandLineArgs: ["--w", root.path],
|
||||
@@ -211,14 +213,14 @@ describe("unittests:: tsc-watch:: resolutionCache:: tsc-watch module resolution
|
||||
});
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: "works when module resolution changes to ambient module",
|
||||
commandLineArgs: ["-w", "/a/b/foo.ts"],
|
||||
sys: () => ts.tscWatch.createWatchedSystem([{
|
||||
sys: () => createWatchedSystem([{
|
||||
path: "/a/b/foo.ts",
|
||||
content: `import * as fs from "fs";`
|
||||
}, ts.tscWatch.libFile], { currentDirectory: "/a/b" }),
|
||||
}, libFile], { currentDirectory: "/a/b" }),
|
||||
changes: [
|
||||
{
|
||||
caption: "npm install node types",
|
||||
@@ -241,12 +243,12 @@ declare module "fs" {
|
||||
}`
|
||||
});
|
||||
},
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks,
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: "works when included file with ambient module changes",
|
||||
commandLineArgs: ["--w", "/a/b/foo.ts", "/a/b/bar.d.ts"],
|
||||
@@ -269,7 +271,7 @@ declare module "url" {
|
||||
}
|
||||
`
|
||||
};
|
||||
return ts.tscWatch.createWatchedSystem([root, file, ts.tscWatch.libFile], { currentDirectory: "/a/b" });
|
||||
return createWatchedSystem([root, file, libFile], { currentDirectory: "/a/b" });
|
||||
},
|
||||
changes: [
|
||||
{
|
||||
@@ -281,30 +283,30 @@ declare module "fs" {
|
||||
}
|
||||
}
|
||||
`),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks,
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: "works when reusing program with files from external library",
|
||||
commandLineArgs: ["--w", "-p", "/a/b/projects/myProject/src"],
|
||||
sys: () => {
|
||||
const configDir = "/a/b/projects/myProject/src/";
|
||||
const file1: ts.tscWatch.File = {
|
||||
const file1: File = {
|
||||
path: configDir + "file1.ts",
|
||||
content: 'import module1 = require("module1");\nmodule1("hello");'
|
||||
};
|
||||
const file2: ts.tscWatch.File = {
|
||||
const file2: File = {
|
||||
path: configDir + "file2.ts",
|
||||
content: 'import module11 = require("module1");\nmodule11("hello");'
|
||||
};
|
||||
const module1: ts.tscWatch.File = {
|
||||
const module1: File = {
|
||||
path: "/a/b/projects/myProject/node_modules/module1/index.js",
|
||||
content: "module.exports = options => { return options.toString(); }"
|
||||
};
|
||||
const configFile: ts.tscWatch.File = {
|
||||
const configFile: File = {
|
||||
path: configDir + "tsconfig.json",
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
@@ -316,67 +318,67 @@ declare module "fs" {
|
||||
}
|
||||
})
|
||||
};
|
||||
return ts.tscWatch.createWatchedSystem([file1, file2, module1, ts.tscWatch.libFile, configFile], { currentDirectory: "/a/b/projects/myProject/" });
|
||||
return createWatchedSystem([file1, file2, module1, libFile, configFile], { currentDirectory: "/a/b/projects/myProject/" });
|
||||
},
|
||||
changes: [
|
||||
{
|
||||
caption: "Add new line to file1",
|
||||
change: sys => sys.appendFile("/a/b/projects/myProject/src/file1.ts", "\n;"),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks,
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: "works when renaming node_modules folder that already contains @types folder",
|
||||
commandLineArgs: ["--w", `${ts.tscWatch.projectRoot}/a.ts`],
|
||||
commandLineArgs: ["--w", `/user/username/projects/myproject/a.ts`],
|
||||
sys: () => {
|
||||
const file: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/a.ts`,
|
||||
const file: File = {
|
||||
path: `/user/username/projects/myproject/a.ts`,
|
||||
content: `import * as q from "qqq";`
|
||||
};
|
||||
const module: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules2/@types/qqq/index.d.ts`,
|
||||
const module: File = {
|
||||
path: `/user/username/projects/myproject/node_modules2/@types/qqq/index.d.ts`,
|
||||
content: "export {}"
|
||||
};
|
||||
return ts.tscWatch.createWatchedSystem([file, ts.tscWatch.libFile, module], { currentDirectory: ts.tscWatch.projectRoot });
|
||||
return createWatchedSystem([file, libFile, module], { currentDirectory: "/user/username/projects/myproject" });
|
||||
},
|
||||
changes: [
|
||||
{
|
||||
caption: "npm install",
|
||||
change: sys => sys.renameFolder(`${ts.tscWatch.projectRoot}/node_modules2`, `${ts.tscWatch.projectRoot}/node_modules`),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks,
|
||||
change: sys => sys.renameFolder(`/user/username/projects/myproject/node_modules2`, `/user/username/projects/myproject/node_modules`),
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
describe("ignores files/folder changes in node_modules that start with '.'", () => {
|
||||
function verifyIgnore(subScenario: string, commandLineArgs: readonly string[]) {
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: `ignores changes in node_modules that start with dot/${subScenario}`,
|
||||
commandLineArgs,
|
||||
sys: () => {
|
||||
const file1: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/test.ts`,
|
||||
const file1: File = {
|
||||
path: `/user/username/projects/myproject/test.ts`,
|
||||
content: `import { x } from "somemodule";`
|
||||
};
|
||||
const file2: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/somemodule/index.d.ts`,
|
||||
const file2: File = {
|
||||
path: `/user/username/projects/myproject/node_modules/somemodule/index.d.ts`,
|
||||
content: `export const x = 10;`
|
||||
};
|
||||
const config: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const config: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: "{}"
|
||||
};
|
||||
return ts.tscWatch.createWatchedSystem([ts.tscWatch.libFile, file1, file2, config]);
|
||||
return createWatchedSystem([libFile, file1, file2, config]);
|
||||
},
|
||||
changes: [
|
||||
{
|
||||
caption: "npm install file and folder that start with '.'",
|
||||
change: sys => sys.ensureFileOrFolder({
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/.cache/babel-loader/89c02171edab901b9926470ba6d5677e.ts`,
|
||||
path: `/user/username/projects/myproject/node_modules/.cache/babel-loader/89c02171edab901b9926470ba6d5677e.ts`,
|
||||
content: JSON.stringify({ something: 10 })
|
||||
}),
|
||||
timeouts: sys => sys.checkTimeoutQueueLength(0),
|
||||
@@ -384,21 +386,21 @@ declare module "fs" {
|
||||
]
|
||||
});
|
||||
}
|
||||
verifyIgnore("watch without configFile", ["--w", `${ts.tscWatch.projectRoot}/test.ts`]);
|
||||
verifyIgnore("watch with configFile", ["--w", "-p", `${ts.tscWatch.projectRoot}/tsconfig.json`]);
|
||||
verifyIgnore("watch without configFile", ["--w", `/user/username/projects/myproject/test.ts`]);
|
||||
verifyIgnore("watch with configFile", ["--w", "-p", `/user/username/projects/myproject/tsconfig.json`]);
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: "when types in compiler option are global and installed at later point",
|
||||
commandLineArgs: ["--w", "-p", `${ts.tscWatch.projectRoot}/tsconfig.json`],
|
||||
commandLineArgs: ["--w", "-p", `/user/username/projects/myproject/tsconfig.json`],
|
||||
sys: () => {
|
||||
const app: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/lib/app.ts`,
|
||||
const app: File = {
|
||||
path: `/user/username/projects/myproject/lib/app.ts`,
|
||||
content: `myapp.component("hello");`
|
||||
};
|
||||
const tsconfig: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const tsconfig: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
module: "none",
|
||||
@@ -406,21 +408,21 @@ declare module "fs" {
|
||||
}
|
||||
})
|
||||
};
|
||||
return ts.tscWatch.createWatchedSystem([app, tsconfig, ts.tscWatch.libFile]);
|
||||
return createWatchedSystem([app, tsconfig, libFile]);
|
||||
},
|
||||
changes: [
|
||||
{
|
||||
caption: "npm install ts-types",
|
||||
change: sys => {
|
||||
sys.ensureFileOrFolder({
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/@myapp/ts-types/package.json`,
|
||||
path: `/user/username/projects/myproject/node_modules/@myapp/ts-types/package.json`,
|
||||
content: JSON.stringify({
|
||||
version: "1.65.1",
|
||||
types: "types/somefile.define.d.ts"
|
||||
})
|
||||
});
|
||||
sys.ensureFileOrFolder({
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/@myapp/ts-types/types/somefile.define.d.ts`,
|
||||
path: `/user/username/projects/myproject/node_modules/@myapp/ts-types/types/somefile.define.d.ts`,
|
||||
content: `
|
||||
declare namespace myapp {
|
||||
function component(str: string): number;
|
||||
@@ -445,63 +447,63 @@ declare namespace myapp {
|
||||
]
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: "with modules linked to sibling folder",
|
||||
commandLineArgs: ["-w"],
|
||||
sys: () => {
|
||||
const mainPackageRoot = `${ts.tscWatch.projectRoot}/main`;
|
||||
const linkedPackageRoot = `${ts.tscWatch.projectRoot}/linked-package`;
|
||||
const mainFile: ts.tscWatch.File = {
|
||||
const mainPackageRoot = `/user/username/projects/myproject/main`;
|
||||
const linkedPackageRoot = `/user/username/projects/myproject/linked-package`;
|
||||
const mainFile: File = {
|
||||
path: `${mainPackageRoot}/index.ts`,
|
||||
content: "import { Foo } from '@scoped/linked-package'"
|
||||
};
|
||||
const config: ts.tscWatch.File = {
|
||||
const config: File = {
|
||||
path: `${mainPackageRoot}/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { module: "commonjs", moduleResolution: "node", baseUrl: ".", rootDir: "." },
|
||||
files: ["index.ts"]
|
||||
})
|
||||
};
|
||||
const linkedPackageInMain: ts.tscWatch.SymLink = {
|
||||
const linkedPackageInMain: SymLink = {
|
||||
path: `${mainPackageRoot}/node_modules/@scoped/linked-package`,
|
||||
symLink: `${linkedPackageRoot}`
|
||||
};
|
||||
const linkedPackageJson: ts.tscWatch.File = {
|
||||
const linkedPackageJson: File = {
|
||||
path: `${linkedPackageRoot}/package.json`,
|
||||
content: JSON.stringify({ name: "@scoped/linked-package", version: "0.0.1", types: "dist/index.d.ts", main: "dist/index.js" })
|
||||
};
|
||||
const linkedPackageIndex: ts.tscWatch.File = {
|
||||
const linkedPackageIndex: File = {
|
||||
path: `${linkedPackageRoot}/dist/index.d.ts`,
|
||||
content: "export * from './other';"
|
||||
};
|
||||
const linkedPackageOther: ts.tscWatch.File = {
|
||||
const linkedPackageOther: File = {
|
||||
path: `${linkedPackageRoot}/dist/other.d.ts`,
|
||||
content: 'export declare const Foo = "BAR";'
|
||||
};
|
||||
const files = [ts.tscWatch.libFile, mainFile, config, linkedPackageInMain, linkedPackageJson, linkedPackageIndex, linkedPackageOther];
|
||||
return ts.tscWatch.createWatchedSystem(files, { currentDirectory: mainPackageRoot });
|
||||
const files = [libFile, mainFile, config, linkedPackageInMain, linkedPackageJson, linkedPackageIndex, linkedPackageOther];
|
||||
return createWatchedSystem(files, { currentDirectory: mainPackageRoot });
|
||||
},
|
||||
changes: ts.emptyArray
|
||||
});
|
||||
|
||||
describe("works when installing something in node_modules or @types when there is no notification from fs for index file", () => {
|
||||
function getNodeAtTypes() {
|
||||
const nodeAtTypesIndex: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/@types/node/index.d.ts`,
|
||||
const nodeAtTypesIndex: File = {
|
||||
path: `/user/username/projects/myproject/node_modules/@types/node/index.d.ts`,
|
||||
content: `/// <reference path="base.d.ts" />`
|
||||
};
|
||||
const nodeAtTypesBase: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/@types/node/base.d.ts`,
|
||||
const nodeAtTypesBase: File = {
|
||||
path: `/user/username/projects/myproject/node_modules/@types/node/base.d.ts`,
|
||||
content: `// Base definitions for all NodeJS modules that are not specific to any version of TypeScript:
|
||||
/// <reference path="ts3.6/base.d.ts" />`
|
||||
};
|
||||
const nodeAtTypes36Base: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/@types/node/ts3.6/base.d.ts`,
|
||||
const nodeAtTypes36Base: File = {
|
||||
path: `/user/username/projects/myproject/node_modules/@types/node/ts3.6/base.d.ts`,
|
||||
content: `/// <reference path="../globals.d.ts" />`
|
||||
};
|
||||
const nodeAtTypesGlobals: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/@types/node/globals.d.ts`,
|
||||
const nodeAtTypesGlobals: File = {
|
||||
path: `/user/username/projects/myproject/node_modules/@types/node/globals.d.ts`,
|
||||
content: `declare var process: NodeJS.Process;
|
||||
declare namespace NodeJS {
|
||||
interface Process {
|
||||
@@ -511,40 +513,40 @@ declare namespace NodeJS {
|
||||
};
|
||||
return { nodeAtTypesIndex, nodeAtTypesBase, nodeAtTypes36Base, nodeAtTypesGlobals };
|
||||
}
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: "works when installing something in node_modules or @types when there is no notification from fs for index file",
|
||||
commandLineArgs: ["--w", `--extendedDiagnostics`],
|
||||
sys: () => {
|
||||
const file: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/worker.ts`,
|
||||
const file: File = {
|
||||
path: `/user/username/projects/myproject/worker.ts`,
|
||||
content: `process.on("uncaughtException");`
|
||||
};
|
||||
const tsconfig: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const tsconfig: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: "{}"
|
||||
};
|
||||
const { nodeAtTypesIndex, nodeAtTypesBase, nodeAtTypes36Base, nodeAtTypesGlobals } = getNodeAtTypes();
|
||||
return ts.tscWatch.createWatchedSystem([file, ts.tscWatch.libFile, tsconfig, nodeAtTypesIndex, nodeAtTypesBase, nodeAtTypes36Base, nodeAtTypesGlobals], { currentDirectory: ts.tscWatch.projectRoot });
|
||||
return createWatchedSystem([file, libFile, tsconfig, nodeAtTypesIndex, nodeAtTypesBase, nodeAtTypes36Base, nodeAtTypesGlobals], { currentDirectory: "/user/username/projects/myproject" });
|
||||
},
|
||||
changes: [
|
||||
{
|
||||
caption: "npm ci step one: remove all node_modules files",
|
||||
change: sys => sys.deleteFolder(`${ts.tscWatch.projectRoot}/node_modules/@types`, /*recursive*/ true),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks,
|
||||
change: sys => sys.deleteFolder(`/user/username/projects/myproject/node_modules/@types`, /*recursive*/ true),
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
},
|
||||
{
|
||||
caption: `npm ci step two: create atTypes but something else in the @types folder`,
|
||||
change: sys => sys.ensureFileOrFolder({
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/@types/mocha/index.d.ts`,
|
||||
path: `/user/username/projects/myproject/node_modules/@types/mocha/index.d.ts`,
|
||||
content: `export const foo = 10;`
|
||||
}),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks()
|
||||
},
|
||||
{
|
||||
caption: `npm ci step three: create atTypes node folder`,
|
||||
change: sys => sys.ensureFileOrFolder({ path: `${ts.tscWatch.projectRoot}/node_modules/@types/node` }),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks
|
||||
change: sys => sys.ensureFileOrFolder({ path: `/user/username/projects/myproject/node_modules/@types/node` }),
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks()
|
||||
},
|
||||
{
|
||||
caption: `npm ci step four: create atTypes write all the files but dont invoke watcher for index.d.ts`,
|
||||
|
||||
@@ -1,29 +1,31 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { createWatchedSystem, File, FileOrFolderOrSymLink, getTsBuildProjectFile, libFile, SymLink } from "../virtualFileSystemWithWatch";
|
||||
import { libContent } from "../tsc/helpers";
|
||||
import { createBaseline, createWatchCompilerHostOfConfigFileForBaseline, runWatchBaseline, solutionBuildWithBaseline } from "./helpers";
|
||||
|
||||
import getFileFromProject = ts.TestFSWithWatch.getTsBuildProjectFile;
|
||||
describe("unittests:: tsc-watch:: watchAPI:: with sourceOfProjectReferenceRedirect", () => {
|
||||
interface VerifyWatchInput {
|
||||
files: readonly ts.TestFSWithWatch.FileOrFolderOrSymLink[];
|
||||
files: readonly FileOrFolderOrSymLink[];
|
||||
config: string;
|
||||
subScenario: string;
|
||||
}
|
||||
|
||||
function verifyWatch({ files, config, subScenario }: VerifyWatchInput, alreadyBuilt: boolean) {
|
||||
const { sys, baseline, oldSnap, cb, getPrograms } = ts.tscWatch.createBaseline(
|
||||
ts.tscWatch.createWatchedSystem(files),
|
||||
const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(
|
||||
createWatchedSystem(files),
|
||||
alreadyBuilt ? (sys, originalRead) => {
|
||||
ts.tscWatch.solutionBuildWithBaseline(sys, [config], originalRead);
|
||||
solutionBuildWithBaseline(sys, [config], originalRead);
|
||||
sys.clearOutput();
|
||||
} : undefined
|
||||
);
|
||||
const host = ts.tscWatch.createWatchCompilerHostOfConfigFileForBaseline({
|
||||
const host = createWatchCompilerHostOfConfigFileForBaseline({
|
||||
configFileName: config,
|
||||
system: sys,
|
||||
cb,
|
||||
});
|
||||
host.useSourceOfProjectReferenceRedirect = ts.returnTrue;
|
||||
const watch = ts.createWatchProgram(host);
|
||||
ts.tscWatch.runWatchBaseline({
|
||||
runWatchBaseline({
|
||||
scenario: "sourceOfProjectReferenceRedirect",
|
||||
subScenario: `${subScenario}${alreadyBuilt ? " when solution is already built" : ""}`,
|
||||
commandLineArgs: ["--w", "--p", config],
|
||||
@@ -48,15 +50,15 @@ describe("unittests:: tsc-watch:: watchAPI:: with sourceOfProjectReferenceRedire
|
||||
|
||||
describe("with simple project", () => {
|
||||
verifyScenario(() => {
|
||||
const baseConfig = getFileFromProject("demo", "tsconfig-base.json");
|
||||
const coreTs = getFileFromProject("demo", "core/utilities.ts");
|
||||
const coreConfig = getFileFromProject("demo", "core/tsconfig.json");
|
||||
const animalTs = getFileFromProject("demo", "animals/animal.ts");
|
||||
const dogTs = getFileFromProject("demo", "animals/dog.ts");
|
||||
const indexTs = getFileFromProject("demo", "animals/index.ts");
|
||||
const animalsConfig = getFileFromProject("demo", "animals/tsconfig.json");
|
||||
const baseConfig = getTsBuildProjectFile("demo", "tsconfig-base.json");
|
||||
const coreTs = getTsBuildProjectFile("demo", "core/utilities.ts");
|
||||
const coreConfig = getTsBuildProjectFile("demo", "core/tsconfig.json");
|
||||
const animalTs = getTsBuildProjectFile("demo", "animals/animal.ts");
|
||||
const dogTs = getTsBuildProjectFile("demo", "animals/dog.ts");
|
||||
const indexTs = getTsBuildProjectFile("demo", "animals/index.ts");
|
||||
const animalsConfig = getTsBuildProjectFile("demo", "animals/tsconfig.json");
|
||||
return {
|
||||
files: [{ path: ts.tscWatch.libFile.path, content: ts.libContent }, baseConfig, coreTs, coreConfig, animalTs, dogTs, indexTs, animalsConfig],
|
||||
files: [{ path: libFile.path, content: libContent }, baseConfig, coreTs, coreConfig, animalTs, dogTs, indexTs, animalsConfig],
|
||||
config: animalsConfig.path,
|
||||
subScenario: "with simple project"
|
||||
};
|
||||
@@ -65,11 +67,11 @@ describe("unittests:: tsc-watch:: watchAPI:: with sourceOfProjectReferenceRedire
|
||||
|
||||
describe("when references are monorepo like with symlinks", () => {
|
||||
interface Packages {
|
||||
bPackageJson: ts.tscWatch.File;
|
||||
aTest: ts.tscWatch.File;
|
||||
bFoo: ts.tscWatch.File;
|
||||
bBar: ts.tscWatch.File;
|
||||
bSymlink: ts.tscWatch.SymLink;
|
||||
bPackageJson: File;
|
||||
aTest: File;
|
||||
bFoo: File;
|
||||
bBar: File;
|
||||
bSymlink: SymLink;
|
||||
subScenario: string;
|
||||
}
|
||||
function verifySymlinkScenario(packages: () => Packages) {
|
||||
@@ -87,16 +89,16 @@ describe("unittests:: tsc-watch:: watchAPI:: with sourceOfProjectReferenceRedire
|
||||
const aConfig = config("A", extraOptions, ["../B"]);
|
||||
const bConfig = config("B", extraOptions);
|
||||
return {
|
||||
files: [ts.tscWatch.libFile, bPackageJson, aConfig, bConfig, aTest, bFoo, bBar, bSymlink],
|
||||
files: [libFile, bPackageJson, aConfig, bConfig, aTest, bFoo, bBar, bSymlink],
|
||||
config: aConfig.path,
|
||||
subScenario: `${subScenario}${extraOptions.preserveSymlinks ? " with preserveSymlinks" : ""}`
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function config(packageName: string, extraOptions: ts.CompilerOptions, references?: string[]): ts.tscWatch.File {
|
||||
function config(packageName: string, extraOptions: ts.CompilerOptions, references?: string[]): File {
|
||||
return {
|
||||
path: `${ts.tscWatch.projectRoot}/packages/${packageName}/tsconfig.json`,
|
||||
path: `/user/username/projects/myproject/packages/${packageName}/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
outDir: "lib",
|
||||
@@ -110,9 +112,9 @@ describe("unittests:: tsc-watch:: watchAPI:: with sourceOfProjectReferenceRedire
|
||||
};
|
||||
}
|
||||
|
||||
function file(packageName: string, fileName: string, content: string): ts.tscWatch.File {
|
||||
function file(packageName: string, fileName: string, content: string): File {
|
||||
return {
|
||||
path: `${ts.tscWatch.projectRoot}/packages/${packageName}/src/${fileName}`,
|
||||
path: `/user/username/projects/myproject/packages/${packageName}/src/${fileName}`,
|
||||
content
|
||||
};
|
||||
}
|
||||
@@ -121,7 +123,7 @@ describe("unittests:: tsc-watch:: watchAPI:: with sourceOfProjectReferenceRedire
|
||||
describe("when packageJson has types field", () => {
|
||||
verifySymlinkScenario(() => ({
|
||||
bPackageJson: {
|
||||
path: `${ts.tscWatch.projectRoot}/packages/B/package.json`,
|
||||
path: `/user/username/projects/myproject/packages/B/package.json`,
|
||||
content: JSON.stringify({
|
||||
main: "lib/index.js",
|
||||
types: "lib/index.d.ts"
|
||||
@@ -135,8 +137,8 @@ bar();
|
||||
bFoo: file("B", "index.ts", `export function foo() { }`),
|
||||
bBar: file("B", "bar.ts", `export function bar() { }`),
|
||||
bSymlink: {
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/${scope}b`,
|
||||
symLink: `${ts.tscWatch.projectRoot}/packages/B`
|
||||
path: `/user/username/projects/myproject/node_modules/${scope}b`,
|
||||
symLink: `/user/username/projects/myproject/packages/B`
|
||||
},
|
||||
subScenario: `when packageJson has types field${scope ? " with scoped package" : ""}`
|
||||
}));
|
||||
@@ -145,7 +147,7 @@ bar();
|
||||
describe("when referencing file from subFolder", () => {
|
||||
verifySymlinkScenario(() => ({
|
||||
bPackageJson: {
|
||||
path: `${ts.tscWatch.projectRoot}/packages/B/package.json`,
|
||||
path: `/user/username/projects/myproject/packages/B/package.json`,
|
||||
content: "{}"
|
||||
},
|
||||
aTest: file("A", "test.ts", `import { foo } from '${scope}b/lib/foo';
|
||||
@@ -156,8 +158,8 @@ bar();
|
||||
bFoo: file("B", "foo.ts", `export function foo() { }`),
|
||||
bBar: file("B", "bar/foo.ts", `export function bar() { }`),
|
||||
bSymlink: {
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/${scope}b`,
|
||||
symLink: `${ts.tscWatch.projectRoot}/packages/B`
|
||||
path: `/user/username/projects/myproject/node_modules/${scope}b`,
|
||||
symLink: `/user/username/projects/myproject/packages/B`
|
||||
},
|
||||
subScenario: `when referencing file from subFolder${scope ? " with scoped package" : ""}`
|
||||
}));
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as Harness from "../../_namespaces/Harness";
|
||||
import { createWatchedSystem, File, libFile, TestServerHostTrackingWrittenFiles } from "../virtualFileSystemWithWatch";
|
||||
import { applyChange, createBaseline, createWatchCompilerHostOfConfigFileForBaseline, runWatchBaseline, watchBaseline } from "./helpers";
|
||||
import { commandLineCallbacks } from "../tsc/helpers";
|
||||
|
||||
describe("unittests:: tsc-watch:: watchAPI:: tsc-watch with custom module resolution", () => {
|
||||
it("verify that module resolution with json extension works when returned without extension", () => {
|
||||
@@ -7,23 +10,23 @@ describe("unittests:: tsc-watch:: watchAPI:: tsc-watch with custom module resolu
|
||||
compilerOptions: { module: "commonjs", resolveJsonModule: true },
|
||||
files: ["index.ts"]
|
||||
};
|
||||
const mainFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/index.ts`,
|
||||
const mainFile: File = {
|
||||
path: `/user/username/projects/myproject/index.ts`,
|
||||
content: "import settings from './settings.json';"
|
||||
};
|
||||
const config: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const config: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: JSON.stringify(configFileJson)
|
||||
};
|
||||
const settingsJson: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/settings.json`,
|
||||
const settingsJson: File = {
|
||||
path: `/user/username/projects/myproject/settings.json`,
|
||||
content: JSON.stringify({ content: "Print this" })
|
||||
};
|
||||
const { sys, baseline, oldSnap, cb, getPrograms } = ts.tscWatch.createBaseline(ts.tscWatch.createWatchedSystem(
|
||||
[ts.tscWatch.libFile, mainFile, config, settingsJson],
|
||||
{ currentDirectory: ts.tscWatch.projectRoot }),
|
||||
const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem(
|
||||
[libFile, mainFile, config, settingsJson],
|
||||
{ currentDirectory: "/user/username/projects/myproject" }),
|
||||
);
|
||||
const host = ts.tscWatch.createWatchCompilerHostOfConfigFileForBaseline({
|
||||
const host = createWatchCompilerHostOfConfigFileForBaseline({
|
||||
configFileName: config.path,
|
||||
system: sys,
|
||||
cb,
|
||||
@@ -39,7 +42,7 @@ describe("unittests:: tsc-watch:: watchAPI:: tsc-watch with custom module resolu
|
||||
};
|
||||
});
|
||||
const watch = ts.createWatchProgram(host);
|
||||
ts.tscWatch.runWatchBaseline({
|
||||
runWatchBaseline({
|
||||
scenario: "watchApi",
|
||||
subScenario: "verify that module resolution with json extension works when returned without extension",
|
||||
commandLineArgs: ["--w", "--p", config.path],
|
||||
@@ -55,26 +58,26 @@ describe("unittests:: tsc-watch:: watchAPI:: tsc-watch with custom module resolu
|
||||
describe("hasInvalidatedResolutions", () => {
|
||||
function verifyWatch(subScenario: string, implementHasInvalidatedResolution: boolean) {
|
||||
it(subScenario, () => {
|
||||
const { sys, baseline, oldSnap, cb, getPrograms } = ts.tscWatch.createBaseline(ts.tscWatch.createWatchedSystem({
|
||||
[`${ts.tscWatch.projectRoot}/tsconfig.json`]: JSON.stringify({
|
||||
const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem({
|
||||
[`/user/username/projects/myproject/tsconfig.json`]: JSON.stringify({
|
||||
compilerOptions: { traceResolution: true, extendedDiagnostics: true },
|
||||
files: ["main.ts"]
|
||||
}),
|
||||
[`${ts.tscWatch.projectRoot}/main.ts`]: `import { foo } from "./other";`,
|
||||
[`${ts.tscWatch.projectRoot}/other.d.ts`]: "export function foo(): void;",
|
||||
[ts.tscWatch.libFile.path]: ts.tscWatch.libFile.content,
|
||||
}, { currentDirectory: ts.tscWatch.projectRoot }));
|
||||
const host = ts.tscWatch.createWatchCompilerHostOfConfigFileForBaseline({
|
||||
configFileName: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
[`/user/username/projects/myproject/main.ts`]: `import { foo } from "./other";`,
|
||||
[`/user/username/projects/myproject/other.d.ts`]: "export function foo(): void;",
|
||||
[libFile.path]: libFile.content,
|
||||
}, { currentDirectory: "/user/username/projects/myproject" }));
|
||||
const host = createWatchCompilerHostOfConfigFileForBaseline({
|
||||
configFileName: `/user/username/projects/myproject/tsconfig.json`,
|
||||
system: sys,
|
||||
cb,
|
||||
});
|
||||
host.resolveModuleNames = (moduleNames, containingFile, _reusedNames, _redirectedReference, options) =>
|
||||
moduleNames.map(m => ts.resolveModuleName(m, containingFile, options, host).resolvedModule);
|
||||
// Invalidate resolutions only when ts file is created
|
||||
if (implementHasInvalidatedResolution) host.hasInvalidatedResolutions = () => sys.fileExists(`${ts.tscWatch.projectRoot}/other.ts`);
|
||||
if (implementHasInvalidatedResolution) host.hasInvalidatedResolutions = () => sys.fileExists(`/user/username/projects/myproject/other.ts`);
|
||||
const watch = ts.createWatchProgram(host);
|
||||
ts.tscWatch.runWatchBaseline({
|
||||
runWatchBaseline({
|
||||
scenario: "watchApi",
|
||||
subScenario,
|
||||
commandLineArgs: ["--w"],
|
||||
@@ -85,19 +88,19 @@ describe("unittests:: tsc-watch:: watchAPI:: tsc-watch with custom module resolu
|
||||
changes: [
|
||||
{
|
||||
caption: "write other with same contents",
|
||||
change: sys => sys.appendFile(`${ts.tscWatch.projectRoot}/other.d.ts`, ""),
|
||||
change: sys => sys.appendFile(`/user/username/projects/myproject/other.d.ts`, ""),
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
},
|
||||
{
|
||||
caption: "change other file",
|
||||
change: sys => sys.appendFile(`${ts.tscWatch.projectRoot}/other.d.ts`, "export function bar(): void;"),
|
||||
change: sys => sys.appendFile(`/user/username/projects/myproject/other.d.ts`, "export function bar(): void;"),
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
},
|
||||
{
|
||||
caption: "write other with same contents but write ts file",
|
||||
change: sys => {
|
||||
sys.appendFile(`${ts.tscWatch.projectRoot}/other.d.ts`, "");
|
||||
sys.writeFile(`${ts.tscWatch.projectRoot}/other.ts`, "export function foo() {}");
|
||||
sys.appendFile(`/user/username/projects/myproject/other.d.ts`, "");
|
||||
sys.writeFile(`/user/username/projects/myproject/other.ts`, "export function foo() {}");
|
||||
},
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
},
|
||||
@@ -113,22 +116,22 @@ describe("unittests:: tsc-watch:: watchAPI:: tsc-watch with custom module resolu
|
||||
|
||||
describe("unittests:: tsc-watch:: watchAPI:: tsc-watch expose error count to watch status reporter", () => {
|
||||
it("verify that the error count is correctly passed down to the watch status reporter", () => {
|
||||
const config: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const config: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { module: "commonjs" },
|
||||
files: ["index.ts"]
|
||||
})
|
||||
};
|
||||
const mainFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/index.ts`,
|
||||
const mainFile: File = {
|
||||
path: `/user/username/projects/myproject/index.ts`,
|
||||
content: "let compiler = new Compiler(); for (let i = 0; j < 5; i++) {}"
|
||||
};
|
||||
const { sys, baseline, oldSnap, cb, getPrograms } = ts.tscWatch.createBaseline(ts.tscWatch.createWatchedSystem(
|
||||
[ts.tscWatch.libFile, mainFile, config],
|
||||
{ currentDirectory: ts.tscWatch.projectRoot }),
|
||||
const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem(
|
||||
[libFile, mainFile, config],
|
||||
{ currentDirectory: "/user/username/projects/myproject" }),
|
||||
);
|
||||
const host = ts.tscWatch.createWatchCompilerHostOfConfigFileForBaseline({
|
||||
const host = createWatchCompilerHostOfConfigFileForBaseline({
|
||||
configFileName: config.path,
|
||||
system: sys,
|
||||
cb,
|
||||
@@ -141,7 +144,7 @@ describe("unittests:: tsc-watch:: watchAPI:: tsc-watch expose error count to wat
|
||||
};
|
||||
const watch = ts.createWatchProgram(host);
|
||||
assert.equal(watchedErrorCount, 2, "The error count was expected to be 2 for the file change");
|
||||
ts.tscWatch.runWatchBaseline({
|
||||
runWatchBaseline({
|
||||
scenario: "watchApi",
|
||||
subScenario: "verify that the error count is correctly passed down to the watch status reporter",
|
||||
commandLineArgs: ["--w", "--p", config.path],
|
||||
@@ -157,16 +160,16 @@ describe("unittests:: tsc-watch:: watchAPI:: tsc-watch expose error count to wat
|
||||
|
||||
describe("unittests:: tsc-watch:: watchAPI:: when watchHost does not implement setTimeout or clearTimeout", () => {
|
||||
it("verifies that getProgram gets updated program if new file is added to the program", () => {
|
||||
const config: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const config: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: "{}"
|
||||
};
|
||||
const mainFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/main.ts`,
|
||||
const mainFile: File = {
|
||||
path: `/user/username/projects/myproject/main.ts`,
|
||||
content: "const x = 10;"
|
||||
};
|
||||
const { sys, baseline, oldSnap, cb, getPrograms } = ts.tscWatch.createBaseline(ts.tscWatch.createWatchedSystem([config, mainFile, ts.tscWatch.libFile]));
|
||||
const host = ts.tscWatch.createWatchCompilerHostOfConfigFileForBaseline({
|
||||
const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem([config, mainFile, libFile]));
|
||||
const host = createWatchCompilerHostOfConfigFileForBaseline({
|
||||
configFileName: config.path,
|
||||
system: sys,
|
||||
cb,
|
||||
@@ -174,7 +177,7 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost does not implement s
|
||||
host.setTimeout = undefined;
|
||||
host.clearTimeout = undefined;
|
||||
const watch = ts.createWatchProgram(host);
|
||||
ts.tscWatch.runWatchBaseline({
|
||||
runWatchBaseline({
|
||||
scenario: "watchApi",
|
||||
subScenario: "without timesouts on host program gets updated",
|
||||
commandLineArgs: ["--w", "--p", config.path],
|
||||
@@ -184,7 +187,7 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost does not implement s
|
||||
getPrograms,
|
||||
changes: [{
|
||||
caption: "Write a file",
|
||||
change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/bar.ts`, "const y =10;"),
|
||||
change: sys => sys.writeFile(`/user/username/projects/myproject/bar.ts`, "const y =10;"),
|
||||
timeouts: sys => {
|
||||
sys.checkTimeoutQueueLength(0);
|
||||
watch.getProgram();
|
||||
@@ -197,22 +200,22 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost does not implement s
|
||||
|
||||
describe("unittests:: tsc-watch:: watchAPI:: when watchHost can add extraFileExtensions to process", () => {
|
||||
it("verifies that extraFileExtensions are supported to get the program with other extensions", () => {
|
||||
const config: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const config: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: "{}"
|
||||
};
|
||||
const mainFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/main.ts`,
|
||||
const mainFile: File = {
|
||||
path: `/user/username/projects/myproject/main.ts`,
|
||||
content: "const x = 10;"
|
||||
};
|
||||
const otherFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/other.vue`,
|
||||
const otherFile: File = {
|
||||
path: `/user/username/projects/myproject/other.vue`,
|
||||
content: ""
|
||||
};
|
||||
const { sys, baseline, oldSnap, cb, getPrograms } = ts.tscWatch.createBaseline(
|
||||
ts.tscWatch.createWatchedSystem([config, mainFile, otherFile, ts.tscWatch.libFile])
|
||||
const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(
|
||||
createWatchedSystem([config, mainFile, otherFile, libFile])
|
||||
);
|
||||
const host = ts.tscWatch.createWatchCompilerHostOfConfigFileForBaseline({
|
||||
const host = createWatchCompilerHostOfConfigFileForBaseline({
|
||||
configFileName: config.path,
|
||||
optionsToExtend: { allowNonTsExtensions: true },
|
||||
extraFileExtensions: [{ extension: ".vue", isMixedContent: true, scriptKind: ts.ScriptKind.Deferred }],
|
||||
@@ -220,7 +223,7 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost can add extraFileExt
|
||||
cb,
|
||||
});
|
||||
const watch = ts.createWatchProgram(host);
|
||||
ts.tscWatch.runWatchBaseline({
|
||||
runWatchBaseline({
|
||||
scenario: "watchApi",
|
||||
subScenario: "extraFileExtensions are supported",
|
||||
commandLineArgs: ["--w", "--p", config.path],
|
||||
@@ -230,8 +233,8 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost can add extraFileExt
|
||||
getPrograms,
|
||||
changes: [{
|
||||
caption: "Write a file",
|
||||
change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/other2.vue`, otherFile.content),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
change: sys => sys.writeFile(`/user/username/projects/myproject/other2.vue`, otherFile.content),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
}],
|
||||
watchOrSolution: watch
|
||||
});
|
||||
@@ -240,20 +243,20 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost can add extraFileExt
|
||||
|
||||
describe("unittests:: tsc-watch:: watchAPI:: when watchHost uses createSemanticDiagnosticsBuilderProgram", () => {
|
||||
function createSystem(configText: string, mainText: string) {
|
||||
const config: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const config: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: configText
|
||||
};
|
||||
const mainFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/main.ts`,
|
||||
const mainFile: File = {
|
||||
path: `/user/username/projects/myproject/main.ts`,
|
||||
content: mainText
|
||||
};
|
||||
const otherFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/other.ts`,
|
||||
const otherFile: File = {
|
||||
path: `/user/username/projects/myproject/other.ts`,
|
||||
content: "export const y = 10;"
|
||||
};
|
||||
return {
|
||||
...ts.tscWatch.createBaseline(ts.tscWatch.createWatchedSystem([config, mainFile, otherFile, ts.tscWatch.libFile])),
|
||||
...createBaseline(createWatchedSystem([config, mainFile, otherFile, libFile])),
|
||||
config,
|
||||
mainFile,
|
||||
otherFile,
|
||||
@@ -262,15 +265,15 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost uses createSemanticD
|
||||
|
||||
function createWatch<T extends ts.BuilderProgram>(
|
||||
baseline: string[],
|
||||
config: ts.tscWatch.File,
|
||||
sys: ts.TestFSWithWatch.TestServerHostTrackingWrittenFiles,
|
||||
config: File,
|
||||
sys: TestServerHostTrackingWrittenFiles,
|
||||
createProgram: ts.CreateProgram<T>,
|
||||
optionsToExtend?: ts.CompilerOptions,
|
||||
) {
|
||||
const { cb, getPrograms } = ts.commandLineCallbacks(sys);
|
||||
const { cb, getPrograms } = commandLineCallbacks(sys);
|
||||
baseline.push(`tsc --w${optionsToExtend?.noEmit ? " --noEmit" : ""}`);
|
||||
const oldSnap = sys.snap();
|
||||
const host = ts.tscWatch.createWatchCompilerHostOfConfigFileForBaseline<T>({
|
||||
const host = createWatchCompilerHostOfConfigFileForBaseline<T>({
|
||||
configFileName: config.path,
|
||||
optionsToExtend,
|
||||
createProgram,
|
||||
@@ -278,7 +281,7 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost uses createSemanticD
|
||||
cb,
|
||||
});
|
||||
const watch = ts.createWatchProgram(host);
|
||||
ts.tscWatch.watchBaseline({
|
||||
watchBaseline({
|
||||
baseline,
|
||||
getPrograms,
|
||||
oldPrograms: ts.emptyArray,
|
||||
@@ -290,7 +293,7 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost uses createSemanticD
|
||||
|
||||
function verifyOutputs(baseline: string[], sys: ts.System, emitSys: ts.System) {
|
||||
baseline.push("Checking if output is same as EmitAndSemanticDiagnosticsBuilderProgram::");
|
||||
for (const output of [`${ts.tscWatch.projectRoot}/main.js`, `${ts.tscWatch.projectRoot}/main.d.ts`, `${ts.tscWatch.projectRoot}/other.js`, `${ts.tscWatch.projectRoot}/other.d.ts`, `${ts.tscWatch.projectRoot}/tsconfig.tsbuildinfo`]) {
|
||||
for (const output of [`/user/username/projects/myproject/main.js`, `/user/username/projects/myproject/main.d.ts`, `/user/username/projects/myproject/other.js`, `/user/username/projects/myproject/other.d.ts`, `/user/username/projects/myproject/tsconfig.tsbuildinfo`]) {
|
||||
baseline.push(`Output file text for ${output} is same:: ${sys.readFile(output) === emitSys.readFile(output)}`);
|
||||
}
|
||||
baseline.push("");
|
||||
@@ -305,22 +308,22 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost uses createSemanticD
|
||||
function applyChangeForBuilderTest(
|
||||
baseline: string[],
|
||||
emitBaseline: string[],
|
||||
sys: ts.TestFSWithWatch.TestServerHostTrackingWrittenFiles,
|
||||
emitSys: ts.TestFSWithWatch.TestServerHostTrackingWrittenFiles,
|
||||
change: (sys: ts.TestFSWithWatch.TestServerHostTrackingWrittenFiles) => void,
|
||||
sys: TestServerHostTrackingWrittenFiles,
|
||||
emitSys: TestServerHostTrackingWrittenFiles,
|
||||
change: (sys: TestServerHostTrackingWrittenFiles) => void,
|
||||
caption: string
|
||||
) {
|
||||
// Change file
|
||||
ts.tscWatch.applyChange(sys, baseline, change, caption);
|
||||
ts.tscWatch.applyChange(emitSys, emitBaseline, change, caption);
|
||||
applyChange(sys, baseline, change, caption);
|
||||
applyChange(emitSys, emitBaseline, change, caption);
|
||||
}
|
||||
|
||||
function verifyBuilder<T extends ts.BuilderProgram>(
|
||||
baseline: string[],
|
||||
emitBaseline: string[],
|
||||
config: ts.tscWatch.File,
|
||||
sys: ts.TestFSWithWatch.TestServerHostTrackingWrittenFiles,
|
||||
emitSys: ts.TestFSWithWatch.TestServerHostTrackingWrittenFiles,
|
||||
config: File,
|
||||
sys: TestServerHostTrackingWrittenFiles,
|
||||
emitSys: TestServerHostTrackingWrittenFiles,
|
||||
createProgram: ts.CreateProgram<T>,
|
||||
optionsToExtend?: ts.CompilerOptions) {
|
||||
createWatch(baseline, config, sys, createProgram, optionsToExtend);
|
||||
@@ -330,7 +333,7 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost uses createSemanticD
|
||||
|
||||
it("verifies that noEmit is handled on createSemanticDiagnosticsBuilderProgram and typechecking happens only on affected files", () => {
|
||||
const { sys, baseline, oldSnap, cb, getPrograms, config, mainFile } = createSystem("{}", "export const x = 10;");
|
||||
const host = ts.tscWatch.createWatchCompilerHostOfConfigFileForBaseline({
|
||||
const host = createWatchCompilerHostOfConfigFileForBaseline({
|
||||
configFileName: config.path,
|
||||
optionsToExtend: { noEmit: true },
|
||||
createProgram: ts.createSemanticDiagnosticsBuilderProgram,
|
||||
@@ -338,7 +341,7 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost uses createSemanticD
|
||||
cb,
|
||||
});
|
||||
const watch = ts.createWatchProgram(host);
|
||||
ts.tscWatch.runWatchBaseline({
|
||||
runWatchBaseline({
|
||||
scenario: "watchApi",
|
||||
subScenario: "verifies that noEmit is handled on createSemanticDiagnosticsBuilderProgram",
|
||||
commandLineArgs: ["--w", "--p", config.path],
|
||||
@@ -349,7 +352,7 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost uses createSemanticD
|
||||
changes: [{
|
||||
caption: "Modify a file",
|
||||
change: sys => sys.appendFile(mainFile.path, "\n// SomeComment"),
|
||||
timeouts: ts.tscWatch.runQueuedTimeoutCallbacks,
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
}],
|
||||
watchOrSolution: watch
|
||||
});
|
||||
@@ -441,9 +444,9 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost uses createSemanticD
|
||||
createWatch(baseline, config, sys, ts.createSemanticDiagnosticsBuilderProgram);
|
||||
|
||||
// Fix error and emit
|
||||
ts.tscWatch.applyChange(sys, baseline, sys => sys.writeFile(mainFile.path, "export const x = 10;"), "Fix error");
|
||||
applyChange(sys, baseline, sys => sys.writeFile(mainFile.path, "export const x = 10;"), "Fix error");
|
||||
|
||||
const { cb, getPrograms } = ts.commandLineCallbacks(sys);
|
||||
const { cb, getPrograms } = commandLineCallbacks(sys);
|
||||
const oldSnap = sys.snap();
|
||||
const reportDiagnostic = ts.createDiagnosticReporter(sys, /*pretty*/ true);
|
||||
const reportWatchStatus = ts.createWatchStatusReporter(sys, /*pretty*/ true);
|
||||
@@ -468,7 +471,7 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost uses createSemanticD
|
||||
cb(program);
|
||||
};
|
||||
ts.createWatchProgram(host);
|
||||
ts.tscWatch.watchBaseline({
|
||||
watchBaseline({
|
||||
baseline,
|
||||
getPrograms,
|
||||
oldPrograms: ts.emptyArray,
|
||||
@@ -481,8 +484,8 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost uses createSemanticD
|
||||
|
||||
describe("unittests:: tsc-watch:: watchAPI:: when getParsedCommandLine is implemented", () => {
|
||||
function setup(useSourceOfProjectReferenceRedirect?: () => boolean) {
|
||||
const config1: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/projects/project1/tsconfig.json`,
|
||||
const config1: File = {
|
||||
path: `/user/username/projects/myproject/projects/project1/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
module: "none",
|
||||
@@ -491,16 +494,16 @@ describe("unittests:: tsc-watch:: watchAPI:: when getParsedCommandLine is implem
|
||||
exclude: ["temp"]
|
||||
})
|
||||
};
|
||||
const class1: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/projects/project1/class1.ts`,
|
||||
const class1: File = {
|
||||
path: `/user/username/projects/myproject/projects/project1/class1.ts`,
|
||||
content: `class class1 {}`
|
||||
};
|
||||
const class1Dts: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/projects/project1/class1.d.ts`,
|
||||
const class1Dts: File = {
|
||||
path: `/user/username/projects/myproject/projects/project1/class1.d.ts`,
|
||||
content: `declare class class1 {}`
|
||||
};
|
||||
const config2: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/projects/project2/tsconfig.json`,
|
||||
const config2: File = {
|
||||
path: `/user/username/projects/myproject/projects/project2/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
module: "none",
|
||||
@@ -511,13 +514,13 @@ describe("unittests:: tsc-watch:: watchAPI:: when getParsedCommandLine is implem
|
||||
]
|
||||
})
|
||||
};
|
||||
const class2: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/projects/project2/class2.ts`,
|
||||
const class2: File = {
|
||||
path: `/user/username/projects/myproject/projects/project2/class2.ts`,
|
||||
content: `class class2 {}`
|
||||
};
|
||||
const system = ts.tscWatch.createWatchedSystem([config1, class1, class1Dts, config2, class2, ts.tscWatch.libFile]);
|
||||
const baseline = ts.tscWatch.createBaseline(system);
|
||||
const compilerHost = ts.tscWatch.createWatchCompilerHostOfConfigFileForBaseline({
|
||||
const system = createWatchedSystem([config1, class1, class1Dts, config2, class2, libFile]);
|
||||
const baseline = createBaseline(system);
|
||||
const compilerHost = createWatchCompilerHostOfConfigFileForBaseline({
|
||||
cb: baseline.cb,
|
||||
system,
|
||||
configFileName: config2.path,
|
||||
@@ -543,7 +546,7 @@ describe("unittests:: tsc-watch:: watchAPI:: when getParsedCommandLine is implem
|
||||
|
||||
it("when new file is added to the referenced project with host implementing getParsedCommandLine", () => {
|
||||
const { watch, baseline, config2, calledGetParsedCommandLine } = setup(ts.returnTrue);
|
||||
ts.tscWatch.runWatchBaseline({
|
||||
runWatchBaseline({
|
||||
scenario: "watchApi",
|
||||
subScenario: "when new file is added to the referenced project with host implementing getParsedCommandLine",
|
||||
commandLineArgs: ["--w", "-p", config2.path, "--extendedDiagnostics"],
|
||||
@@ -553,18 +556,18 @@ describe("unittests:: tsc-watch:: watchAPI:: when getParsedCommandLine is implem
|
||||
caption: "Add class3 to project1",
|
||||
change: sys => {
|
||||
calledGetParsedCommandLine.clear();
|
||||
sys.writeFile(`${ts.tscWatch.projectRoot}/projects/project1/class3.ts`, `class class3 {}`);
|
||||
sys.writeFile(`/user/username/projects/myproject/projects/project1/class3.ts`, `class class3 {}`);
|
||||
},
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
},
|
||||
{
|
||||
caption: "Add excluded file to project1",
|
||||
change: sys => sys.ensureFileOrFolder({ path: `${ts.tscWatch.projectRoot}/projects/project1/temp/file.d.ts`, content: `declare class file {}` }),
|
||||
change: sys => sys.ensureFileOrFolder({ path: `/user/username/projects/myproject/projects/project1/temp/file.d.ts`, content: `declare class file {}` }),
|
||||
timeouts: sys => sys.checkTimeoutQueueLength(0),
|
||||
},
|
||||
{
|
||||
caption: "Add output of class3",
|
||||
change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/projects/project1/class3.d.ts`, `declare class class3 {}`),
|
||||
change: sys => sys.writeFile(`/user/username/projects/myproject/projects/project1/class3.d.ts`, `declare class class3 {}`),
|
||||
timeouts: sys => sys.checkTimeoutQueueLength(0),
|
||||
},
|
||||
],
|
||||
@@ -574,7 +577,7 @@ describe("unittests:: tsc-watch:: watchAPI:: when getParsedCommandLine is implem
|
||||
|
||||
it("when new file is added to the referenced project with host implementing getParsedCommandLine without implementing useSourceOfProjectReferenceRedirect", () => {
|
||||
const { watch, baseline, config2, calledGetParsedCommandLine } = setup();
|
||||
ts.tscWatch.runWatchBaseline({
|
||||
runWatchBaseline({
|
||||
scenario: "watchApi",
|
||||
subScenario: "when new file is added to the referenced project with host implementing getParsedCommandLine without implementing useSourceOfProjectReferenceRedirect",
|
||||
commandLineArgs: ["--w", "-p", config2.path, "--extendedDiagnostics"],
|
||||
@@ -584,29 +587,29 @@ describe("unittests:: tsc-watch:: watchAPI:: when getParsedCommandLine is implem
|
||||
caption: "Add class3 to project1",
|
||||
change: sys => {
|
||||
calledGetParsedCommandLine.clear();
|
||||
sys.writeFile(`${ts.tscWatch.projectRoot}/projects/project1/class3.ts`, `class class3 {}`);
|
||||
sys.writeFile(`/user/username/projects/myproject/projects/project1/class3.ts`, `class class3 {}`);
|
||||
},
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
},
|
||||
{
|
||||
caption: "Add class3 output to project1",
|
||||
change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/projects/project1/class3.d.ts`, `declare class class3 {}`),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
change: sys => sys.writeFile(`/user/username/projects/myproject/projects/project1/class3.d.ts`, `declare class class3 {}`),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
},
|
||||
{
|
||||
caption: "Add excluded file to project1",
|
||||
change: sys => sys.ensureFileOrFolder({ path: `${ts.tscWatch.projectRoot}/projects/project1/temp/file.d.ts`, content: `declare class file {}` }),
|
||||
change: sys => sys.ensureFileOrFolder({ path: `/user/username/projects/myproject/projects/project1/temp/file.d.ts`, content: `declare class file {}` }),
|
||||
timeouts: sys => sys.checkTimeoutQueueLength(0),
|
||||
},
|
||||
{
|
||||
caption: "Delete output of class3",
|
||||
change: sys => sys.deleteFile(`${ts.tscWatch.projectRoot}/projects/project1/class3.d.ts`),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
change: sys => sys.deleteFile(`/user/username/projects/myproject/projects/project1/class3.d.ts`),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
},
|
||||
{
|
||||
caption: "Add output of class3",
|
||||
change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/projects/project1/class3.d.ts`, `declare class class3 {}`),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
change: sys => sys.writeFile(`/user/username/projects/myproject/projects/project1/class3.d.ts`, `declare class class3 {}`),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
},
|
||||
],
|
||||
watchOrSolution: watch
|
||||
@@ -617,27 +620,27 @@ describe("unittests:: tsc-watch:: watchAPI:: when getParsedCommandLine is implem
|
||||
describe("unittests:: tsc-watch:: watchAPI:: when builder emit occurs with emitOnlyDtsFiles", () => {
|
||||
function verify(subScenario: string, outFile?: string) {
|
||||
it(subScenario, () => {
|
||||
const system = ts.tscWatch.createWatchedSystem({
|
||||
[`${ts.tscWatch.projectRoot}/tsconfig.json`]: JSON.stringify({
|
||||
const system = createWatchedSystem({
|
||||
[`/user/username/projects/myproject/tsconfig.json`]: JSON.stringify({
|
||||
compilerOptions: { composite: true, noEmitOnError: true, module: "amd", outFile },
|
||||
files: ["a.ts", "b.ts"],
|
||||
}),
|
||||
[`${ts.tscWatch.projectRoot}/a.ts`]: "export const x = 10;",
|
||||
[`${ts.tscWatch.projectRoot}/b.ts`]: "export const y: 10 = 20;",
|
||||
[ts.tscWatch.libFile.path]: ts.tscWatch.libFile.content,
|
||||
}, { currentDirectory: ts.tscWatch.projectRoot });
|
||||
const baseline = ts.tscWatch.createBaseline(system);
|
||||
const compilerHost = ts.tscWatch.createWatchCompilerHostOfConfigFileForBaseline({
|
||||
[`/user/username/projects/myproject/a.ts`]: "export const x = 10;",
|
||||
[`/user/username/projects/myproject/b.ts`]: "export const y: 10 = 20;",
|
||||
[libFile.path]: libFile.content,
|
||||
}, { currentDirectory: "/user/username/projects/myproject" });
|
||||
const baseline = createBaseline(system);
|
||||
const compilerHost = createWatchCompilerHostOfConfigFileForBaseline({
|
||||
cb: baseline.cb,
|
||||
system,
|
||||
configFileName: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
configFileName: `/user/username/projects/myproject/tsconfig.json`,
|
||||
optionsToExtend: { extendedDiagnostics: true }
|
||||
});
|
||||
const originalEmitProgram = compilerHost.afterProgramCreate;
|
||||
compilerHost.afterProgramCreate = myAfterProgramCreate;
|
||||
let callFullEmit = true;
|
||||
const watch = ts.createWatchProgram(compilerHost);
|
||||
ts.tscWatch.runWatchBaseline({
|
||||
runWatchBaseline({
|
||||
scenario: "watchApi",
|
||||
subScenario,
|
||||
commandLineArgs: ["--w", "--extendedDiagnostics"],
|
||||
@@ -646,10 +649,10 @@ describe("unittests:: tsc-watch:: watchAPI:: when builder emit occurs with emitO
|
||||
{
|
||||
caption: "Fix error but run emit with emitOnlyDts",
|
||||
change: sys => {
|
||||
sys.writeFile(`${ts.tscWatch.projectRoot}/b.ts`, `export const y = 10;`);
|
||||
sys.writeFile(`/user/username/projects/myproject/b.ts`, `export const y = 10;`);
|
||||
callFullEmit = false;
|
||||
},
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
},
|
||||
{
|
||||
caption: "Emit with emitOnlyDts shouldnt emit anything",
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { createWatchedSystem, File, libFile, SymLink, TestServerHost, Tsc_WatchDirectory, Tsc_WatchFile } from "../virtualFileSystemWithWatch";
|
||||
import { commonFile1, commonFile2, noopChange, verifyTscWatch } from "./helpers";
|
||||
|
||||
import Tsc_WatchDirectory = ts.TestFSWithWatch.Tsc_WatchDirectory;
|
||||
describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different polling/non polling options", () => {
|
||||
const scenario = "watchEnvironment";
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: "watchFile/using dynamic priority polling",
|
||||
commandLineArgs: ["--w", `/a/username/project/typescript.ts`],
|
||||
sys: () => {
|
||||
const projectFolder = "/a/username/project";
|
||||
const file1: ts.tscWatch.File = {
|
||||
const file1: File = {
|
||||
path: `${projectFolder}/typescript.ts`,
|
||||
content: "var z = 10;"
|
||||
};
|
||||
const environmentVariables = new ts.Map<string, string>();
|
||||
environmentVariables.set("TSC_WATCHFILE", ts.TestFSWithWatch.Tsc_WatchFile.DynamicPolling);
|
||||
return ts.tscWatch.createWatchedSystem([file1, ts.tscWatch.libFile], { environmentVariables });
|
||||
environmentVariables.set("TSC_WATCHFILE", Tsc_WatchFile.DynamicPolling);
|
||||
return createWatchedSystem([file1, libFile], { environmentVariables });
|
||||
},
|
||||
changes: [
|
||||
{
|
||||
@@ -37,7 +38,7 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po
|
||||
// Make a change to file
|
||||
change: sys => sys.writeFile("/a/username/project/typescript.ts", "var zz30 = 100;"),
|
||||
// During this timeout the file would be detected as unchanged
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
},
|
||||
{
|
||||
caption: "Callbacks: medium priority + high priority queue and scheduled program update",
|
||||
@@ -67,12 +68,12 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po
|
||||
]
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: "watchFile/using fixed chunk size polling",
|
||||
commandLineArgs: ["-w", "-p", "/a/b/tsconfig.json"],
|
||||
sys: () => {
|
||||
const configFile: ts.tscWatch.File = {
|
||||
const configFile: File = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: JSON.stringify({
|
||||
watchOptions: {
|
||||
@@ -80,8 +81,8 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po
|
||||
}
|
||||
})
|
||||
};
|
||||
const files = [ts.tscWatch.libFile, ts.tscWatch.commonFile1, ts.tscWatch.commonFile2, configFile];
|
||||
return ts.tscWatch.createWatchedSystem(files);
|
||||
const files = [libFile, commonFile1, commonFile2, configFile];
|
||||
return createWatchedSystem(files);
|
||||
},
|
||||
changes: [
|
||||
{
|
||||
@@ -99,8 +100,8 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po
|
||||
{
|
||||
caption: "Make change to file but should detect as changed and schedule program update",
|
||||
// Make a change to file
|
||||
change: sys => sys.writeFile(ts.tscWatch.commonFile1.path, "var zz30 = 100;"),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun,
|
||||
change: sys => sys.writeFile(commonFile1.path, "var zz30 = 100;"),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
},
|
||||
{
|
||||
caption: "Callbacks: queue and scheduled program update",
|
||||
@@ -125,7 +126,7 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po
|
||||
function verifyRenamingFileInSubFolder(subScenario: string, tscWatchDirectory: Tsc_WatchDirectory) {
|
||||
const projectFolder = "/a/username/project";
|
||||
const projectSrcFolder = `${projectFolder}/src`;
|
||||
const configFile: ts.tscWatch.File = {
|
||||
const configFile: File = {
|
||||
path: `${projectFolder}/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
watchOptions: {
|
||||
@@ -133,19 +134,19 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po
|
||||
}
|
||||
})
|
||||
};
|
||||
const file: ts.tscWatch.File = {
|
||||
const file: File = {
|
||||
path: `${projectSrcFolder}/file1.ts`,
|
||||
content: ""
|
||||
};
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: `watchDirectories/${subScenario}`,
|
||||
commandLineArgs: ["--w", "-p", configFile.path],
|
||||
sys: () => {
|
||||
const files = [file, configFile, ts.tscWatch.libFile];
|
||||
const files = [file, configFile, libFile];
|
||||
const environmentVariables = new ts.Map<string, string>();
|
||||
environmentVariables.set("TSC_WATCHDIRECTORY", tscWatchDirectory);
|
||||
return ts.tscWatch.createWatchedSystem(files, { environmentVariables });
|
||||
return createWatchedSystem(files, { environmentVariables });
|
||||
},
|
||||
changes: [
|
||||
{
|
||||
@@ -172,71 +173,71 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po
|
||||
|
||||
verifyRenamingFileInSubFolder("uses non recursive dynamic polling when renaming file in subfolder", Tsc_WatchDirectory.DynamicPolling);
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: "watchDirectories/when there are symlinks to folders in recursive folders",
|
||||
commandLineArgs: ["--w"],
|
||||
sys: () => {
|
||||
const cwd = "/home/user/projects/myproject";
|
||||
const file1: ts.tscWatch.File = {
|
||||
const file1: File = {
|
||||
path: `${cwd}/src/file.ts`,
|
||||
content: `import * as a from "a"`
|
||||
};
|
||||
const tsconfig: ts.tscWatch.File = {
|
||||
const tsconfig: File = {
|
||||
path: `${cwd}/tsconfig.json`,
|
||||
content: `{ "compilerOptions": { "extendedDiagnostics": true, "traceResolution": true }}`
|
||||
};
|
||||
const realA: ts.tscWatch.File = {
|
||||
const realA: File = {
|
||||
path: `${cwd}/node_modules/reala/index.d.ts`,
|
||||
content: `export {}`
|
||||
};
|
||||
const realB: ts.tscWatch.File = {
|
||||
const realB: File = {
|
||||
path: `${cwd}/node_modules/realb/index.d.ts`,
|
||||
content: `export {}`
|
||||
};
|
||||
const symLinkA: ts.tscWatch.SymLink = {
|
||||
const symLinkA: SymLink = {
|
||||
path: `${cwd}/node_modules/a`,
|
||||
symLink: `${cwd}/node_modules/reala`
|
||||
};
|
||||
const symLinkB: ts.tscWatch.SymLink = {
|
||||
const symLinkB: SymLink = {
|
||||
path: `${cwd}/node_modules/b`,
|
||||
symLink: `${cwd}/node_modules/realb`
|
||||
};
|
||||
const symLinkBInA: ts.tscWatch.SymLink = {
|
||||
const symLinkBInA: SymLink = {
|
||||
path: `${cwd}/node_modules/reala/node_modules/b`,
|
||||
symLink: `${cwd}/node_modules/b`
|
||||
};
|
||||
const symLinkAInB: ts.tscWatch.SymLink = {
|
||||
const symLinkAInB: SymLink = {
|
||||
path: `${cwd}/node_modules/realb/node_modules/a`,
|
||||
symLink: `${cwd}/node_modules/a`
|
||||
};
|
||||
const files = [ts.tscWatch.libFile, file1, tsconfig, realA, realB, symLinkA, symLinkB, symLinkBInA, symLinkAInB];
|
||||
const files = [libFile, file1, tsconfig, realA, realB, symLinkA, symLinkB, symLinkBInA, symLinkAInB];
|
||||
const environmentVariables = new ts.Map<string, string>();
|
||||
environmentVariables.set("TSC_WATCHDIRECTORY", Tsc_WatchDirectory.NonRecursiveWatchDirectory);
|
||||
return ts.tscWatch.createWatchedSystem(files, { environmentVariables, currentDirectory: cwd });
|
||||
return createWatchedSystem(files, { environmentVariables, currentDirectory: cwd });
|
||||
},
|
||||
changes: ts.emptyArray
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: "watchDirectories/with non synchronous watch directory",
|
||||
commandLineArgs: ["--w", "-p", `${ts.tscWatch.projectRoot}/tsconfig.json`],
|
||||
commandLineArgs: ["--w", "-p", `/user/username/projects/myproject/tsconfig.json`],
|
||||
sys: () => {
|
||||
const configFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const configFile: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: "{}"
|
||||
};
|
||||
const file1: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/src/file1.ts`,
|
||||
const file1: File = {
|
||||
path: `/user/username/projects/myproject/src/file1.ts`,
|
||||
content: `import { x } from "file2";`
|
||||
};
|
||||
const file2: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/file2/index.d.ts`,
|
||||
const file2: File = {
|
||||
path: `/user/username/projects/myproject/node_modules/file2/index.d.ts`,
|
||||
content: `export const x = 10;`
|
||||
};
|
||||
const files = [ts.tscWatch.libFile, file1, file2, configFile];
|
||||
return ts.tscWatch.createWatchedSystem(files, { runWithoutRecursiveWatches: true });
|
||||
const files = [libFile, file1, file2, configFile];
|
||||
return createWatchedSystem(files, { runWithoutRecursiveWatches: true });
|
||||
},
|
||||
changes: [
|
||||
{
|
||||
@@ -250,7 +251,7 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po
|
||||
{
|
||||
caption: "Remove directory node_modules",
|
||||
// Remove directory node_modules
|
||||
change: sys => sys.deleteFolder(`${ts.tscWatch.projectRoot}/node_modules`, /*recursive*/ true),
|
||||
change: sys => sys.deleteFolder(`/user/username/projects/myproject/node_modules`, /*recursive*/ true),
|
||||
timeouts: sys => {
|
||||
sys.checkTimeoutQueueLength(3); // 1. Failed lookup invalidation 2. For updating program and 3. for updating child watches
|
||||
sys.runQueuedTimeoutCallbacks(sys.getNextTimeoutId() - 2); // Update program
|
||||
@@ -269,17 +270,17 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po
|
||||
{
|
||||
caption: "Start npm install",
|
||||
// npm install
|
||||
change: sys => sys.createDirectory(`${ts.tscWatch.projectRoot}/node_modules`),
|
||||
change: sys => sys.createDirectory(`/user/username/projects/myproject/node_modules`),
|
||||
timeouts: sys => sys.checkTimeoutQueueLength(1), // To update folder structure
|
||||
},
|
||||
{
|
||||
caption: "npm install folder creation of file2",
|
||||
change: sys => sys.createDirectory(`${ts.tscWatch.projectRoot}/node_modules/file2`),
|
||||
change: sys => sys.createDirectory(`/user/username/projects/myproject/node_modules/file2`),
|
||||
timeouts: sys => sys.checkTimeoutQueueLength(1), // To update folder structure
|
||||
},
|
||||
{
|
||||
caption: "npm install index file in file2",
|
||||
change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/node_modules/file2/index.d.ts`, `export const x = 10;`),
|
||||
change: sys => sys.writeFile(`/user/username/projects/myproject/node_modules/file2/index.d.ts`, `export const x = 10;`),
|
||||
timeouts: sys => sys.checkTimeoutQueueLength(1), // To update folder structure
|
||||
},
|
||||
{
|
||||
@@ -309,32 +310,32 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po
|
||||
],
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: "watchDirectories/with non synchronous watch directory with outDir and declaration enabled",
|
||||
commandLineArgs: ["--w", "-p", `${ts.tscWatch.projectRoot}/tsconfig.json`],
|
||||
commandLineArgs: ["--w", "-p", `/user/username/projects/myproject/tsconfig.json`],
|
||||
sys: () => {
|
||||
const configFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const configFile: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: JSON.stringify({ compilerOptions: { outDir: "dist", declaration: true } })
|
||||
};
|
||||
const file1: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/src/file1.ts`,
|
||||
const file1: File = {
|
||||
path: `/user/username/projects/myproject/src/file1.ts`,
|
||||
content: `import { x } from "file2";`
|
||||
};
|
||||
const file2: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/file2/index.d.ts`,
|
||||
const file2: File = {
|
||||
path: `/user/username/projects/myproject/node_modules/file2/index.d.ts`,
|
||||
content: `export const x = 10;`
|
||||
};
|
||||
const files = [ts.tscWatch.libFile, file1, file2, configFile];
|
||||
return ts.tscWatch.createWatchedSystem(files, { runWithoutRecursiveWatches: true });
|
||||
const files = [libFile, file1, file2, configFile];
|
||||
return createWatchedSystem(files, { runWithoutRecursiveWatches: true });
|
||||
},
|
||||
changes: [
|
||||
ts.tscWatch.noopChange,
|
||||
noopChange,
|
||||
{
|
||||
caption: "Add new file, should schedule and run timeout to update directory watcher",
|
||||
change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/src/file3.ts`, `export const y = 10;`),
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, // Update the child watch
|
||||
change: sys => sys.writeFile(`/user/username/projects/myproject/src/file3.ts`, `export const y = 10;`),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), // Update the child watch
|
||||
},
|
||||
{
|
||||
caption: "Actual program update to include new file",
|
||||
@@ -344,37 +345,37 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po
|
||||
{
|
||||
caption: "After program emit with new file, should schedule and run timeout to update directory watcher",
|
||||
change: ts.noop,
|
||||
timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, // Update the child watch
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), // Update the child watch
|
||||
},
|
||||
ts.tscWatch.noopChange,
|
||||
noopChange,
|
||||
],
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: "watchDirectories/with non synchronous watch directory renaming a file",
|
||||
commandLineArgs: ["--w", "-p", `${ts.tscWatch.projectRoot}/tsconfig.json`],
|
||||
commandLineArgs: ["--w", "-p", `/user/username/projects/myproject/tsconfig.json`],
|
||||
sys: () => {
|
||||
const configFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const configFile: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: JSON.stringify({ compilerOptions: { outDir: "dist" } })
|
||||
};
|
||||
const file1: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/src/file1.ts`,
|
||||
const file1: File = {
|
||||
path: `/user/username/projects/myproject/src/file1.ts`,
|
||||
content: `import { x } from "./file2";`
|
||||
};
|
||||
const file2: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/src/file2.ts`,
|
||||
const file2: File = {
|
||||
path: `/user/username/projects/myproject/src/file2.ts`,
|
||||
content: `export const x = 10;`
|
||||
};
|
||||
const files = [ts.tscWatch.libFile, file1, file2, configFile];
|
||||
return ts.tscWatch.createWatchedSystem(files, { runWithoutRecursiveWatches: true });
|
||||
const files = [libFile, file1, file2, configFile];
|
||||
return createWatchedSystem(files, { runWithoutRecursiveWatches: true });
|
||||
},
|
||||
changes: [
|
||||
ts.tscWatch.noopChange,
|
||||
noopChange,
|
||||
{
|
||||
caption: "rename the file",
|
||||
change: sys => sys.renameFile(`${ts.tscWatch.projectRoot}/src/file2.ts`, `${ts.tscWatch.projectRoot}/src/renamed.ts`),
|
||||
change: sys => sys.renameFile(`/user/username/projects/myproject/src/file2.ts`, `/user/username/projects/myproject/src/renamed.ts`),
|
||||
timeouts: sys => {
|
||||
sys.checkTimeoutQueueLength(2); // 1. For updating program and 2. for updating child watches
|
||||
sys.runQueuedTimeoutCallbacks(1); // Update program
|
||||
@@ -395,12 +396,12 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po
|
||||
});
|
||||
|
||||
describe("handles watch compiler options", () => {
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: "watchOptions/with watchFile option",
|
||||
commandLineArgs: ["-w", "-p", "/a/b/tsconfig.json"],
|
||||
sys: () => {
|
||||
const configFile: ts.tscWatch.File = {
|
||||
const configFile: File = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: JSON.stringify({
|
||||
watchOptions: {
|
||||
@@ -408,18 +409,18 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po
|
||||
}
|
||||
})
|
||||
};
|
||||
const files = [ts.tscWatch.libFile, ts.tscWatch.commonFile1, ts.tscWatch.commonFile2, configFile];
|
||||
return ts.tscWatch.createWatchedSystem(files);
|
||||
const files = [libFile, commonFile1, commonFile2, configFile];
|
||||
return createWatchedSystem(files);
|
||||
},
|
||||
changes: ts.emptyArray
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: "watchOptions/with watchDirectory option",
|
||||
commandLineArgs: ["-w", "-p", "/a/b/tsconfig.json"],
|
||||
sys: () => {
|
||||
const configFile: ts.tscWatch.File = {
|
||||
const configFile: File = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: JSON.stringify({
|
||||
watchOptions: {
|
||||
@@ -427,18 +428,18 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po
|
||||
}
|
||||
})
|
||||
};
|
||||
const files = [ts.tscWatch.libFile, ts.tscWatch.commonFile1, ts.tscWatch.commonFile2, configFile];
|
||||
return ts.tscWatch.createWatchedSystem(files, { runWithoutRecursiveWatches: true });
|
||||
const files = [libFile, commonFile1, commonFile2, configFile];
|
||||
return createWatchedSystem(files, { runWithoutRecursiveWatches: true });
|
||||
},
|
||||
changes: ts.emptyArray
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: "watchOptions/with fallbackPolling option",
|
||||
commandLineArgs: ["-w", "-p", "/a/b/tsconfig.json"],
|
||||
sys: () => {
|
||||
const configFile: ts.tscWatch.File = {
|
||||
const configFile: File = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: JSON.stringify({
|
||||
watchOptions: {
|
||||
@@ -446,59 +447,59 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po
|
||||
}
|
||||
})
|
||||
};
|
||||
const files = [ts.tscWatch.libFile, ts.tscWatch.commonFile1, ts.tscWatch.commonFile2, configFile];
|
||||
return ts.tscWatch.createWatchedSystem(files, { runWithoutRecursiveWatches: true, runWithFallbackPolling: true });
|
||||
const files = [libFile, commonFile1, commonFile2, configFile];
|
||||
return createWatchedSystem(files, { runWithoutRecursiveWatches: true, runWithFallbackPolling: true });
|
||||
},
|
||||
changes: ts.emptyArray
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: "watchOptions/with watchFile as watch options to extend",
|
||||
commandLineArgs: ["-w", "-p", "/a/b/tsconfig.json", "--watchFile", "UseFsEvents"],
|
||||
sys: () => {
|
||||
const configFile: ts.tscWatch.File = {
|
||||
const configFile: File = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: "{}"
|
||||
};
|
||||
const files = [ts.tscWatch.libFile, ts.tscWatch.commonFile1, ts.tscWatch.commonFile2, configFile];
|
||||
return ts.tscWatch.createWatchedSystem(files);
|
||||
const files = [libFile, commonFile1, commonFile2, configFile];
|
||||
return createWatchedSystem(files);
|
||||
},
|
||||
changes: ts.emptyArray
|
||||
});
|
||||
|
||||
describe("exclude options", () => {
|
||||
function sys(watchOptions: ts.WatchOptions, runWithoutRecursiveWatches?: boolean): ts.tscWatch.WatchedSystem {
|
||||
const configFile: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
function sys(watchOptions: ts.WatchOptions, runWithoutRecursiveWatches?: boolean): TestServerHost {
|
||||
const configFile: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: JSON.stringify({ exclude: ["node_modules"], watchOptions })
|
||||
};
|
||||
const main: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/src/main.ts`,
|
||||
const main: File = {
|
||||
path: `/user/username/projects/myproject/src/main.ts`,
|
||||
content: `import { foo } from "bar"; foo();`
|
||||
};
|
||||
const bar: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/bar/index.d.ts`,
|
||||
const bar: File = {
|
||||
path: `/user/username/projects/myproject/node_modules/bar/index.d.ts`,
|
||||
content: `export { foo } from "./foo";`
|
||||
};
|
||||
const foo: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/bar/foo.d.ts`,
|
||||
const foo: File = {
|
||||
path: `/user/username/projects/myproject/node_modules/bar/foo.d.ts`,
|
||||
content: `export function foo(): string;`
|
||||
};
|
||||
const fooBar: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/bar/fooBar.d.ts`,
|
||||
const fooBar: File = {
|
||||
path: `/user/username/projects/myproject/node_modules/bar/fooBar.d.ts`,
|
||||
content: `export function fooBar(): string;`
|
||||
};
|
||||
const temp: ts.tscWatch.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/node_modules/bar/temp/index.d.ts`,
|
||||
const temp: File = {
|
||||
path: `/user/username/projects/myproject/node_modules/bar/temp/index.d.ts`,
|
||||
content: "export function temp(): string;"
|
||||
};
|
||||
const files = [ts.tscWatch.libFile, main, bar, foo, fooBar, temp, configFile];
|
||||
return ts.tscWatch.createWatchedSystem(files, { currentDirectory: ts.tscWatch.projectRoot, runWithoutRecursiveWatches });
|
||||
const files = [libFile, main, bar, foo, fooBar, temp, configFile];
|
||||
return createWatchedSystem(files, { currentDirectory: "/user/username/projects/myproject", runWithoutRecursiveWatches });
|
||||
}
|
||||
|
||||
function verifyWorker(...additionalFlags: string[]) {
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: `watchOptions/with excludeFiles option${additionalFlags.join("")}`,
|
||||
commandLineArgs: ["-w", ...additionalFlags],
|
||||
@@ -506,13 +507,13 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po
|
||||
changes: [
|
||||
{
|
||||
caption: "Change foo",
|
||||
change: sys => ts.tscWatch.replaceFileText(sys, `${ts.tscWatch.projectRoot}/node_modules/bar/foo.d.ts`, "foo", "fooBar"),
|
||||
change: sys => sys.replaceFileText(`/user/username/projects/myproject/node_modules/bar/foo.d.ts`, "foo", "fooBar"),
|
||||
timeouts: sys => sys.checkTimeoutQueueLength(0),
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: `watchOptions/with excludeDirectories option${additionalFlags.join("")}`,
|
||||
commandLineArgs: ["-w", ...additionalFlags],
|
||||
@@ -520,12 +521,12 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po
|
||||
changes: [
|
||||
{
|
||||
caption: "delete fooBar",
|
||||
change: sys => sys.deleteFile(`${ts.tscWatch.projectRoot}/node_modules/bar/fooBar.d.ts`),
|
||||
change: sys => sys.deleteFile(`/user/username/projects/myproject/node_modules/bar/fooBar.d.ts`),
|
||||
timeouts: sys => sys.checkTimeoutQueueLength(0), }
|
||||
]
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: `watchOptions/with excludeDirectories option with recursive directory watching${additionalFlags.join("")}`,
|
||||
commandLineArgs: ["-w", ...additionalFlags],
|
||||
@@ -541,7 +542,7 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po
|
||||
},
|
||||
{
|
||||
caption: "add new folder to temp",
|
||||
change: sys => sys.ensureFileOrFolder({ path: `${ts.tscWatch.projectRoot}/node_modules/bar/temp/fooBar/index.d.ts`, content: "export function temp(): string;" }),
|
||||
change: sys => sys.ensureFileOrFolder({ path: `/user/username/projects/myproject/node_modules/bar/temp/fooBar/index.d.ts`, content: "export function temp(): string;" }),
|
||||
timeouts: sys => sys.checkTimeoutQueueLength(0),
|
||||
}
|
||||
]
|
||||
@@ -553,28 +554,28 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po
|
||||
});
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: `fsWatch/when using file watching thats when rename occurs when file is still on the disk`,
|
||||
commandLineArgs: ["-w", "--extendedDiagnostics"],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
sys: () => createWatchedSystem(
|
||||
{
|
||||
[ts.tscWatch.libFile.path]: ts.tscWatch.libFile.content,
|
||||
[`${ts.tscWatch.projectRoot}/main.ts`]: `import { foo } from "./foo"; foo();`,
|
||||
[`${ts.tscWatch.projectRoot}/foo.ts`]: `export declare function foo(): string;`,
|
||||
[`${ts.tscWatch.projectRoot}/tsconfig.json`]: JSON.stringify({
|
||||
[libFile.path]: libFile.content,
|
||||
[`/user/username/projects/myproject/main.ts`]: `import { foo } from "./foo"; foo();`,
|
||||
[`/user/username/projects/myproject/foo.ts`]: `export declare function foo(): string;`,
|
||||
[`/user/username/projects/myproject/tsconfig.json`]: JSON.stringify({
|
||||
watchOptions: { watchFile: "useFsEvents" },
|
||||
files: ["foo.ts", "main.ts"]
|
||||
}),
|
||||
},
|
||||
{ currentDirectory: ts.tscWatch.projectRoot, }
|
||||
{ currentDirectory: "/user/username/projects/myproject", }
|
||||
),
|
||||
changes: [
|
||||
{
|
||||
caption: "Introduce error such that when callback happens file is already appeared",
|
||||
// vm's wq generates this kind of event
|
||||
// Skip delete event so inode changes but when the create's rename occurs file is on disk
|
||||
change: sys => sys.modifyFile(`${ts.tscWatch.projectRoot}/foo.ts`, `export declare function foo2(): string;`, {
|
||||
change: sys => sys.modifyFile(`/user/username/projects/myproject/foo.ts`, `export declare function foo2(): string;`, {
|
||||
invokeFileDeleteCreateAsPartInsteadOfChange: true,
|
||||
ignoreDelete: true,
|
||||
}),
|
||||
@@ -582,89 +583,89 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po
|
||||
},
|
||||
{
|
||||
caption: "Replace file with rename event that fixes error",
|
||||
change: sys => sys.modifyFile(`${ts.tscWatch.projectRoot}/foo.ts`, `export declare function foo(): string;`, { invokeFileDeleteCreateAsPartInsteadOfChange: true, }),
|
||||
change: sys => sys.modifyFile(`/user/username/projects/myproject/foo.ts`, `export declare function foo(): string;`, { invokeFileDeleteCreateAsPartInsteadOfChange: true, }),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
},
|
||||
]
|
||||
});
|
||||
|
||||
describe("with fsWatch on inodes", () => {
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: `fsWatch/when using file watching thats on inode`,
|
||||
commandLineArgs: ["-w", "--extendedDiagnostics"],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
sys: () => createWatchedSystem(
|
||||
{
|
||||
[ts.tscWatch.libFile.path]: ts.tscWatch.libFile.content,
|
||||
[`${ts.tscWatch.projectRoot}/main.ts`]: `import { foo } from "./foo"; foo();`,
|
||||
[`${ts.tscWatch.projectRoot}/foo.d.ts`]: `export function foo(): string;`,
|
||||
[`${ts.tscWatch.projectRoot}/tsconfig.json`]: JSON.stringify({ watchOptions: { watchFile: "useFsEvents" }, files: ["foo.d.ts", "main.ts"] }),
|
||||
[libFile.path]: libFile.content,
|
||||
[`/user/username/projects/myproject/main.ts`]: `import { foo } from "./foo"; foo();`,
|
||||
[`/user/username/projects/myproject/foo.d.ts`]: `export function foo(): string;`,
|
||||
[`/user/username/projects/myproject/tsconfig.json`]: JSON.stringify({ watchOptions: { watchFile: "useFsEvents" }, files: ["foo.d.ts", "main.ts"] }),
|
||||
},
|
||||
{
|
||||
currentDirectory: ts.tscWatch.projectRoot,
|
||||
currentDirectory: "/user/username/projects/myproject",
|
||||
inodeWatching: true
|
||||
}
|
||||
),
|
||||
changes: [
|
||||
{
|
||||
caption: "Replace file with rename event that introduces error",
|
||||
change: sys => sys.modifyFile(`${ts.tscWatch.projectRoot}/foo.d.ts`, `export function foo2(): string;`, { invokeFileDeleteCreateAsPartInsteadOfChange: true }),
|
||||
change: sys => sys.modifyFile(`/user/username/projects/myproject/foo.d.ts`, `export function foo2(): string;`, { invokeFileDeleteCreateAsPartInsteadOfChange: true }),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(2),
|
||||
},
|
||||
{
|
||||
caption: "Replace file with rename event that fixes error",
|
||||
change: sys => sys.modifyFile(`${ts.tscWatch.projectRoot}/foo.d.ts`, `export function foo(): string;`, { invokeFileDeleteCreateAsPartInsteadOfChange: true }),
|
||||
change: sys => sys.modifyFile(`/user/username/projects/myproject/foo.d.ts`, `export function foo(): string;`, { invokeFileDeleteCreateAsPartInsteadOfChange: true }),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(2),
|
||||
},
|
||||
]
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: `fsWatch/when using file watching thats on inode when rename event ends with tilde`,
|
||||
commandLineArgs: ["-w", "--extendedDiagnostics"],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
sys: () => createWatchedSystem(
|
||||
{
|
||||
[ts.tscWatch.libFile.path]: ts.tscWatch.libFile.content,
|
||||
[`${ts.tscWatch.projectRoot}/main.ts`]: `import { foo } from "./foo"; foo();`,
|
||||
[`${ts.tscWatch.projectRoot}/foo.d.ts`]: `export function foo(): string;`,
|
||||
[`${ts.tscWatch.projectRoot}/tsconfig.json`]: JSON.stringify({ watchOptions: { watchFile: "useFsEvents" }, files: ["foo.d.ts", "main.ts"] }),
|
||||
[libFile.path]: libFile.content,
|
||||
[`/user/username/projects/myproject/main.ts`]: `import { foo } from "./foo"; foo();`,
|
||||
[`/user/username/projects/myproject/foo.d.ts`]: `export function foo(): string;`,
|
||||
[`/user/username/projects/myproject/tsconfig.json`]: JSON.stringify({ watchOptions: { watchFile: "useFsEvents" }, files: ["foo.d.ts", "main.ts"] }),
|
||||
},
|
||||
{
|
||||
currentDirectory: ts.tscWatch.projectRoot,
|
||||
currentDirectory: "/user/username/projects/myproject",
|
||||
inodeWatching: true
|
||||
}
|
||||
),
|
||||
changes: [
|
||||
{
|
||||
caption: "Replace file with rename event that introduces error",
|
||||
change: sys => sys.modifyFile(`${ts.tscWatch.projectRoot}/foo.d.ts`, `export function foo2(): string;`, { invokeFileDeleteCreateAsPartInsteadOfChange: true, useTildeAsSuffixInRenameEventFileName: true }),
|
||||
change: sys => sys.modifyFile(`/user/username/projects/myproject/foo.d.ts`, `export function foo2(): string;`, { invokeFileDeleteCreateAsPartInsteadOfChange: true, useTildeAsSuffixInRenameEventFileName: true }),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(2),
|
||||
},
|
||||
{
|
||||
caption: "Replace file with rename event that fixes error",
|
||||
change: sys => sys.modifyFile(`${ts.tscWatch.projectRoot}/foo.d.ts`, `export function foo(): string;`, { invokeFileDeleteCreateAsPartInsteadOfChange: true, useTildeAsSuffixInRenameEventFileName: true }),
|
||||
change: sys => sys.modifyFile(`/user/username/projects/myproject/foo.d.ts`, `export function foo(): string;`, { invokeFileDeleteCreateAsPartInsteadOfChange: true, useTildeAsSuffixInRenameEventFileName: true }),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(2),
|
||||
},
|
||||
]
|
||||
});
|
||||
|
||||
ts.tscWatch.verifyTscWatch({
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: `fsWatch/when using file watching thats on inode when rename occurs when file is still on the disk`,
|
||||
commandLineArgs: ["-w", "--extendedDiagnostics"],
|
||||
sys: () => ts.tscWatch.createWatchedSystem(
|
||||
sys: () => createWatchedSystem(
|
||||
{
|
||||
[ts.tscWatch.libFile.path]: ts.tscWatch.libFile.content,
|
||||
[`${ts.tscWatch.projectRoot}/main.ts`]: `import { foo } from "./foo"; foo();`,
|
||||
[`${ts.tscWatch.projectRoot}/foo.ts`]: `export declare function foo(): string;`,
|
||||
[`${ts.tscWatch.projectRoot}/tsconfig.json`]: JSON.stringify({
|
||||
[libFile.path]: libFile.content,
|
||||
[`/user/username/projects/myproject/main.ts`]: `import { foo } from "./foo"; foo();`,
|
||||
[`/user/username/projects/myproject/foo.ts`]: `export declare function foo(): string;`,
|
||||
[`/user/username/projects/myproject/tsconfig.json`]: JSON.stringify({
|
||||
watchOptions: { watchFile: "useFsEvents" },
|
||||
files: ["foo.ts", "main.ts"]
|
||||
}),
|
||||
},
|
||||
{
|
||||
currentDirectory: ts.tscWatch.projectRoot,
|
||||
currentDirectory: "/user/username/projects/myproject",
|
||||
inodeWatching: true,
|
||||
}
|
||||
),
|
||||
@@ -673,7 +674,7 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po
|
||||
caption: "Introduce error such that when callback happens file is already appeared",
|
||||
// vm's wq generates this kind of event
|
||||
// Skip delete event so inode changes but when the create's rename occurs file is on disk
|
||||
change: sys => sys.modifyFile(`${ts.tscWatch.projectRoot}/foo.ts`, `export declare function foo2(): string;`, {
|
||||
change: sys => sys.modifyFile(`/user/username/projects/myproject/foo.ts`, `export declare function foo2(): string;`, {
|
||||
invokeFileDeleteCreateAsPartInsteadOfChange: true,
|
||||
ignoreDelete: true,
|
||||
skipInodeCheckOnCreate: true
|
||||
@@ -682,7 +683,7 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po
|
||||
},
|
||||
{
|
||||
caption: "Replace file with rename event that fixes error",
|
||||
change: sys => sys.modifyFile(`${ts.tscWatch.projectRoot}/foo.ts`, `export declare function foo(): string;`, { invokeFileDeleteCreateAsPartInsteadOfChange: true, }),
|
||||
change: sys => sys.modifyFile(`/user/username/projects/myproject/foo.ts`, `export declare function foo(): string;`, { invokeFileDeleteCreateAsPartInsteadOfChange: true, }),
|
||||
timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1),
|
||||
},
|
||||
]
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { createServerHost, File, libFile } from "../virtualFileSystemWithWatch";
|
||||
import { commonFile1, commonFile2 } from "../tscWatch/helpers";
|
||||
import { TestSession, createSession } from "./helpers";
|
||||
|
||||
describe("unittests:: tsserver:: applyChangesToOpenFiles", () => {
|
||||
const configFile: ts.projectSystem.File = {
|
||||
const configFile: File = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: "{}"
|
||||
};
|
||||
const file3: ts.projectSystem.File = {
|
||||
const file3: File = {
|
||||
path: "/a/b/file3.ts",
|
||||
content: "let xyz = 1;"
|
||||
};
|
||||
const app: ts.projectSystem.File = {
|
||||
const app: File = {
|
||||
path: "/a/b/app.ts",
|
||||
content: "let z = 1;"
|
||||
};
|
||||
|
||||
function fileContentWithComment(file: ts.projectSystem.File) {
|
||||
function fileContentWithComment(file: File) {
|
||||
return `// some copy right notice
|
||||
${file.content}`;
|
||||
}
|
||||
@@ -31,22 +34,22 @@ ${file.content}`;
|
||||
}
|
||||
|
||||
interface Verify {
|
||||
applyChangesToOpen: (session: ts.projectSystem.TestSession) => void;
|
||||
openFile1Again: (session: ts.projectSystem.TestSession) => void;
|
||||
applyChangesToOpen: (session: TestSession) => void;
|
||||
openFile1Again: (session: TestSession) => void;
|
||||
}
|
||||
function verify({ applyChangesToOpen, openFile1Again }: Verify) {
|
||||
const host = ts.projectSystem.createServerHost([app, file3, ts.projectSystem.commonFile1, ts.projectSystem.commonFile2, ts.projectSystem.libFile, configFile]);
|
||||
const session = ts.projectSystem.createSession(host);
|
||||
session.executeCommandSeq<ts.projectSystem.protocol.OpenRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.Open,
|
||||
const host = createServerHost([app, file3, commonFile1, commonFile2, libFile, configFile]);
|
||||
const session = createSession(host);
|
||||
session.executeCommandSeq<ts.server.protocol.OpenRequest>({
|
||||
command: ts.server.protocol.CommandTypes.Open,
|
||||
arguments: { file: app.path }
|
||||
});
|
||||
const service = session.getProjectService();
|
||||
const project = service.configuredProjects.get(configFile.path)!;
|
||||
assert.isDefined(project);
|
||||
verifyProjectVersion(project, 1);
|
||||
session.executeCommandSeq<ts.projectSystem.protocol.OpenRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.Open,
|
||||
session.executeCommandSeq<ts.server.protocol.OpenRequest>({
|
||||
command: ts.server.protocol.CommandTypes.Open,
|
||||
arguments: {
|
||||
file: file3.path,
|
||||
fileContent: fileContentWithComment(file3)
|
||||
@@ -55,8 +58,8 @@ ${file.content}`;
|
||||
verifyProjectVersion(project, 2);
|
||||
|
||||
// Verify Texts
|
||||
verifyText(service, ts.projectSystem.commonFile1.path, ts.projectSystem.commonFile1.content);
|
||||
verifyText(service, ts.projectSystem.commonFile2.path, ts.projectSystem.commonFile2.content);
|
||||
verifyText(service, commonFile1.path, commonFile1.content);
|
||||
verifyText(service, commonFile2.path, commonFile2.content);
|
||||
verifyText(service, app.path, app.content);
|
||||
verifyText(service, file3.path, fileContentWithComment(file3));
|
||||
|
||||
@@ -66,36 +69,36 @@ ${file.content}`;
|
||||
// Verify again
|
||||
verifyProjectVersion(project, 3);
|
||||
// Open file contents
|
||||
verifyText(service, ts.projectSystem.commonFile1.path, fileContentWithComment(ts.projectSystem.commonFile1));
|
||||
verifyText(service, ts.projectSystem.commonFile2.path, fileContentWithComment(ts.projectSystem.commonFile2));
|
||||
verifyText(service, commonFile1.path, fileContentWithComment(commonFile1));
|
||||
verifyText(service, commonFile2.path, fileContentWithComment(commonFile2));
|
||||
verifyText(service, app.path, "let zzz = 10;let zz = 10;let z = 1;");
|
||||
verifyText(service, file3.path, file3.content);
|
||||
|
||||
// Open file1 again
|
||||
openFile1Again(session);
|
||||
assert.isTrue(service.getScriptInfo(ts.projectSystem.commonFile1.path)!.isScriptOpen());
|
||||
assert.isTrue(service.getScriptInfo(commonFile1.path)!.isScriptOpen());
|
||||
|
||||
// Verify that file1 contents are changed
|
||||
verifyProjectVersion(project, 4);
|
||||
verifyText(service, ts.projectSystem.commonFile1.path, ts.projectSystem.commonFile1.content);
|
||||
verifyText(service, ts.projectSystem.commonFile2.path, fileContentWithComment(ts.projectSystem.commonFile2));
|
||||
verifyText(service, commonFile1.path, commonFile1.content);
|
||||
verifyText(service, commonFile2.path, fileContentWithComment(commonFile2));
|
||||
verifyText(service, app.path, "let zzz = 10;let zz = 10;let z = 1;");
|
||||
verifyText(service, file3.path, file3.content);
|
||||
}
|
||||
|
||||
it("with applyChangedToOpenFiles request", () => {
|
||||
verify({
|
||||
applyChangesToOpen: session => session.executeCommandSeq<ts.projectSystem.protocol.ApplyChangedToOpenFilesRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.ApplyChangedToOpenFiles,
|
||||
applyChangesToOpen: session => session.executeCommandSeq<ts.server.protocol.ApplyChangedToOpenFilesRequest>({
|
||||
command: ts.server.protocol.CommandTypes.ApplyChangedToOpenFiles,
|
||||
arguments: {
|
||||
openFiles: [
|
||||
{
|
||||
fileName: ts.projectSystem.commonFile1.path,
|
||||
content: fileContentWithComment(ts.projectSystem.commonFile1)
|
||||
fileName: commonFile1.path,
|
||||
content: fileContentWithComment(commonFile1)
|
||||
},
|
||||
{
|
||||
fileName: ts.projectSystem.commonFile2.path,
|
||||
content: fileContentWithComment(ts.projectSystem.commonFile2)
|
||||
fileName: commonFile2.path,
|
||||
content: fileContentWithComment(commonFile2)
|
||||
}
|
||||
],
|
||||
changedFiles: [
|
||||
@@ -118,12 +121,12 @@ ${file.content}`;
|
||||
]
|
||||
}
|
||||
}),
|
||||
openFile1Again: session => session.executeCommandSeq<ts.projectSystem.protocol.ApplyChangedToOpenFilesRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.ApplyChangedToOpenFiles,
|
||||
openFile1Again: session => session.executeCommandSeq<ts.server.protocol.ApplyChangedToOpenFilesRequest>({
|
||||
command: ts.server.protocol.CommandTypes.ApplyChangedToOpenFiles,
|
||||
arguments: {
|
||||
openFiles: [{
|
||||
fileName: ts.projectSystem.commonFile1.path,
|
||||
content: ts.projectSystem.commonFile1.content
|
||||
fileName: commonFile1.path,
|
||||
content: commonFile1.content
|
||||
}]
|
||||
}
|
||||
}),
|
||||
@@ -132,17 +135,17 @@ ${file.content}`;
|
||||
|
||||
it("with updateOpen request", () => {
|
||||
verify({
|
||||
applyChangesToOpen: session => session.executeCommandSeq<ts.projectSystem.protocol.UpdateOpenRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.UpdateOpen,
|
||||
applyChangesToOpen: session => session.executeCommandSeq<ts.server.protocol.UpdateOpenRequest>({
|
||||
command: ts.server.protocol.CommandTypes.UpdateOpen,
|
||||
arguments: {
|
||||
openFiles: [
|
||||
{
|
||||
file: ts.projectSystem.commonFile1.path,
|
||||
fileContent: fileContentWithComment(ts.projectSystem.commonFile1)
|
||||
file: commonFile1.path,
|
||||
fileContent: fileContentWithComment(commonFile1)
|
||||
},
|
||||
{
|
||||
file: ts.projectSystem.commonFile2.path,
|
||||
fileContent: fileContentWithComment(ts.projectSystem.commonFile2)
|
||||
file: commonFile2.path,
|
||||
fileContent: fileContentWithComment(commonFile2)
|
||||
}
|
||||
],
|
||||
changedFiles: [
|
||||
@@ -167,12 +170,12 @@ ${file.content}`;
|
||||
]
|
||||
}
|
||||
}),
|
||||
openFile1Again: session => session.executeCommandSeq<ts.projectSystem.protocol.UpdateOpenRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.UpdateOpen,
|
||||
openFile1Again: session => session.executeCommandSeq<ts.server.protocol.UpdateOpenRequest>({
|
||||
command: ts.server.protocol.CommandTypes.UpdateOpen,
|
||||
arguments: {
|
||||
openFiles: [{
|
||||
file: ts.projectSystem.commonFile1.path,
|
||||
fileContent: ts.projectSystem.commonFile1.content
|
||||
file: commonFile1.path,
|
||||
fileContent: commonFile1.content
|
||||
}]
|
||||
}
|
||||
}),
|
||||
|
||||
@@ -1,30 +1,32 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { createServerHost, File } from "../virtualFileSystemWithWatch";
|
||||
import { openFilesForSession, checkNumberOfInferredProjects, checkNumberOfConfiguredProjects, createSession } from "./helpers";
|
||||
|
||||
const angularFormsDts: ts.projectSystem.File = {
|
||||
const angularFormsDts: File = {
|
||||
path: "/node_modules/@angular/forms/forms.d.ts",
|
||||
content: "export declare class PatternValidator {}",
|
||||
};
|
||||
const angularFormsPackageJson: ts.projectSystem.File = {
|
||||
const angularFormsPackageJson: File = {
|
||||
path: "/node_modules/@angular/forms/package.json",
|
||||
content: `{ "name": "@angular/forms", "typings": "./forms.d.ts" }`,
|
||||
};
|
||||
const angularCoreDts: ts.projectSystem.File = {
|
||||
const angularCoreDts: File = {
|
||||
path: "/node_modules/@angular/core/core.d.ts",
|
||||
content: "",
|
||||
};
|
||||
const angularCorePackageJson: ts.projectSystem.File = {
|
||||
const angularCorePackageJson: File = {
|
||||
path: "/node_modules/@angular/core/package.json",
|
||||
content: `{ "name": "@angular/core", "typings": "./core.d.ts" }`,
|
||||
};
|
||||
const tsconfig: ts.projectSystem.File = {
|
||||
const tsconfig: File = {
|
||||
path: "/tsconfig.json",
|
||||
content: `{ "compilerOptions": { "module": "commonjs" } }`,
|
||||
};
|
||||
const packageJson: ts.projectSystem.File = {
|
||||
const packageJson: File = {
|
||||
path: "/package.json",
|
||||
content: `{ "dependencies": { "@angular/forms": "*", "@angular/core": "*" } }`
|
||||
};
|
||||
const indexTs: ts.projectSystem.File = {
|
||||
const indexTs: File = {
|
||||
path: "/index.ts",
|
||||
content: ""
|
||||
};
|
||||
@@ -38,7 +40,7 @@ describe("unittests:: tsserver:: autoImportProvider", () => {
|
||||
{ path: packageJson.path, content: `{ "dependencies": {} }` },
|
||||
indexTs
|
||||
]);
|
||||
ts.projectSystem.openFilesForSession([indexTs], session);
|
||||
openFilesForSession([indexTs], session);
|
||||
assert.isUndefined(projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider());
|
||||
});
|
||||
|
||||
@@ -50,7 +52,7 @@ describe("unittests:: tsserver:: autoImportProvider", () => {
|
||||
packageJson,
|
||||
{ path: indexTs.path, content: "import '@angular/forms';" }
|
||||
]);
|
||||
ts.projectSystem.openFilesForSession([indexTs], session);
|
||||
openFilesForSession([indexTs], session);
|
||||
assert.isUndefined(projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider());
|
||||
});
|
||||
|
||||
@@ -64,9 +66,9 @@ describe("unittests:: tsserver:: autoImportProvider", () => {
|
||||
{ path: "/node_modules/@angular/core/core.d.ts", content: `export namespace angular {};` },
|
||||
]);
|
||||
|
||||
ts.projectSystem.openFilesForSession([angularFormsDts], session);
|
||||
ts.projectSystem.checkNumberOfInferredProjects(projectService, 1);
|
||||
ts.projectSystem.checkNumberOfConfiguredProjects(projectService, 0);
|
||||
openFilesForSession([angularFormsDts], session);
|
||||
checkNumberOfInferredProjects(projectService, 1);
|
||||
checkNumberOfConfiguredProjects(projectService, 0);
|
||||
assert.isUndefined(projectService
|
||||
.getDefaultProjectForFile(angularFormsDts.path as ts.server.NormalizedPath, /*ensureProject*/ true)!
|
||||
.getLanguageService()
|
||||
@@ -75,9 +77,9 @@ describe("unittests:: tsserver:: autoImportProvider", () => {
|
||||
|
||||
it("Auto-importable file is in inferred project until imported", () => {
|
||||
const { projectService, session, updateFile } = setup([angularFormsDts, angularFormsPackageJson, tsconfig, packageJson, indexTs]);
|
||||
ts.projectSystem.checkNumberOfInferredProjects(projectService, 0);
|
||||
ts.projectSystem.openFilesForSession([angularFormsDts], session);
|
||||
ts.projectSystem.checkNumberOfInferredProjects(projectService, 1);
|
||||
checkNumberOfInferredProjects(projectService, 0);
|
||||
openFilesForSession([angularFormsDts], session);
|
||||
checkNumberOfInferredProjects(projectService, 1);
|
||||
assert.equal(
|
||||
projectService.getDefaultProjectForFile(angularFormsDts.path as ts.server.NormalizedPath, /*ensureProject*/ true)?.projectKind,
|
||||
ts.server.ProjectKind.Inferred);
|
||||
@@ -99,7 +101,7 @@ describe("unittests:: tsserver:: autoImportProvider", () => {
|
||||
indexTs
|
||||
]);
|
||||
|
||||
ts.projectSystem.openFilesForSession([indexTs], session);
|
||||
openFilesForSession([indexTs], session);
|
||||
assert.isUndefined(projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider());
|
||||
|
||||
host.writeFile(packageJson.path, packageJson.content);
|
||||
@@ -115,7 +117,7 @@ describe("unittests:: tsserver:: autoImportProvider", () => {
|
||||
indexTs
|
||||
]);
|
||||
|
||||
ts.projectSystem.openFilesForSession([indexTs], session);
|
||||
openFilesForSession([indexTs], session);
|
||||
const autoImportProvider = projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider();
|
||||
assert.ok(autoImportProvider);
|
||||
|
||||
@@ -134,7 +136,7 @@ describe("unittests:: tsserver:: autoImportProvider", () => {
|
||||
indexTs
|
||||
]);
|
||||
|
||||
ts.projectSystem.openFilesForSession([indexTs], session);
|
||||
openFilesForSession([indexTs], session);
|
||||
const hostProject = projectService.configuredProjects.get(tsconfig.path)!;
|
||||
hostProject.getPackageJsonAutoImportProvider();
|
||||
const autoImportProviderProject = hostProject.autoImportProviderHost;
|
||||
@@ -154,7 +156,7 @@ describe("unittests:: tsserver:: autoImportProvider", () => {
|
||||
]);
|
||||
|
||||
// Create configured project only, ensure !projectService.pendingEnsureProjectForOpenFiles
|
||||
ts.projectSystem.openFilesForSession([indexTs], session);
|
||||
openFilesForSession([indexTs], session);
|
||||
const hostProject = projectService.configuredProjects.get(tsconfig.path)!;
|
||||
projectService.delayEnsureProjectForOpenFiles();
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
@@ -177,7 +179,7 @@ describe("unittests:: tsserver:: autoImportProvider", () => {
|
||||
indexTs
|
||||
]);
|
||||
|
||||
ts.projectSystem.openFilesForSession([indexTs], session);
|
||||
openFilesForSession([indexTs], session);
|
||||
const project = projectService.configuredProjects.get(tsconfig.path)!;
|
||||
const completionsBefore = project.getLanguageService().getCompletionsAtPosition(indexTs.path, 0, { includeCompletionsForModuleExports: true });
|
||||
assert.isTrue(completionsBefore?.entries.some(c => c.name === "PatternValidator"));
|
||||
@@ -204,7 +206,7 @@ describe("unittests:: tsserver:: autoImportProvider", () => {
|
||||
indexTs
|
||||
]);
|
||||
|
||||
ts.projectSystem.openFilesForSession([indexTs, angularFormsDts], session);
|
||||
openFilesForSession([indexTs, angularFormsDts], session);
|
||||
const project = projectService.configuredProjects.get(tsconfig.path)!;
|
||||
const completionsBefore = project.getLanguageService().getCompletionsAtPosition(indexTs.path, 0, { includeCompletionsForModuleExports: true });
|
||||
assert.isTrue(completionsBefore?.entries.some(c => c.name === "PatternValidator"));
|
||||
@@ -224,7 +226,7 @@ describe("unittests:: tsserver:: autoImportProvider", () => {
|
||||
indexTs
|
||||
]);
|
||||
|
||||
ts.projectSystem.openFilesForSession([indexTs], session);
|
||||
openFilesForSession([indexTs], session);
|
||||
assert.isUndefined(projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider());
|
||||
|
||||
host.writeFile(packageJson.path, packageJson.content);
|
||||
@@ -232,7 +234,7 @@ describe("unittests:: tsserver:: autoImportProvider", () => {
|
||||
});
|
||||
|
||||
it("Does not create an auto import provider if there are too many dependencies", () => {
|
||||
const createPackage = (i: number): ts.projectSystem.File[] => ([
|
||||
const createPackage = (i: number): File[] => ([
|
||||
{ path: `/node_modules/package${i}/package.json`, content: `{ "name": "package${i}" }` },
|
||||
{ path: `/node_modules/package${i}/index.d.ts`, content: `` }
|
||||
]);
|
||||
@@ -243,10 +245,10 @@ describe("unittests:: tsserver:: autoImportProvider", () => {
|
||||
}
|
||||
|
||||
const dependencies = packages.reduce((hash, p) => ({ ...hash, [JSON.parse(p[0].content).name]: "*" }), {});
|
||||
const packageJson: ts.projectSystem.File = { path: "/package.json", content: JSON.stringify(dependencies) };
|
||||
const { projectService, session } = setup([ ...ts.flatten(packages), indexTs, tsconfig, packageJson ]);
|
||||
const packageJson: File = { path: "/package.json", content: JSON.stringify(dependencies) };
|
||||
const { projectService, session } = setup([...ts.flatten(packages), indexTs, tsconfig, packageJson]);
|
||||
|
||||
ts.projectSystem.openFilesForSession([indexTs], session);
|
||||
openFilesForSession([indexTs], session);
|
||||
const project = projectService.configuredProjects.get(tsconfig.path)!;
|
||||
assert.isUndefined(project.getPackageJsonAutoImportProvider());
|
||||
});
|
||||
@@ -276,10 +278,10 @@ describe("unittests:: tsserver:: autoImportProvider - monorepo", () => {
|
||||
|
||||
const { projectService, session, findAllReferences } = setup(files);
|
||||
|
||||
ts.projectSystem.openFilesForSession([files.find(f => f.path === "/packages/b/index.ts")!], session);
|
||||
ts.projectSystem.checkNumberOfConfiguredProjects(projectService, 2); // Solution (no files), B
|
||||
openFilesForSession([files.find(f => f.path === "/packages/b/index.ts")!], session);
|
||||
checkNumberOfConfiguredProjects(projectService, 2); // Solution (no files), B
|
||||
findAllReferences("/packages/b/index.ts", 1, "export class B".length - 1);
|
||||
ts.projectSystem.checkNumberOfConfiguredProjects(projectService, 3); // Solution (no files), A, B
|
||||
checkNumberOfConfiguredProjects(projectService, 3); // Solution (no files), A, B
|
||||
|
||||
// Project for A is created - ensure it doesn't have an autoImportProvider
|
||||
assert.isUndefined(projectService.configuredProjects.get("/packages/a/tsconfig.json")!.getLanguageService().getAutoImportProvider());
|
||||
@@ -299,7 +301,7 @@ describe("unittests:: tsserver:: autoImportProvider - monorepo", () => {
|
||||
];
|
||||
|
||||
const { projectService, session } = setup(files);
|
||||
ts.projectSystem.openFilesForSession([files[2]], session);
|
||||
openFilesForSession([files[2]], session);
|
||||
assert.isDefined(projectService.configuredProjects.get("/packages/a/tsconfig.json")!.getPackageJsonAutoImportProvider());
|
||||
assert.isDefined(projectService.configuredProjects.get("/packages/a/tsconfig.json")!.getPackageJsonAutoImportProvider());
|
||||
});
|
||||
@@ -314,9 +316,9 @@ describe("unittests:: tsserver:: autoImportProvider - monorepo", () => {
|
||||
});
|
||||
});
|
||||
|
||||
function setup(files: ts.projectSystem.File[]) {
|
||||
const host = ts.projectSystem.createServerHost(files);
|
||||
const session = ts.projectSystem.createSession(host);
|
||||
function setup(files: File[]) {
|
||||
const host = createServerHost(files);
|
||||
const session = createSession(host);
|
||||
const projectService = session.getProjectService();
|
||||
return {
|
||||
host,
|
||||
@@ -328,8 +330,8 @@ function setup(files: ts.projectSystem.File[]) {
|
||||
|
||||
function updateFile(path: string, newText: string) {
|
||||
ts.Debug.assertIsDefined(files.find(f => f.path === path));
|
||||
session.executeCommandSeq<ts.projectSystem.protocol.ApplyChangedToOpenFilesRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.ApplyChangedToOpenFiles,
|
||||
session.executeCommandSeq<ts.server.protocol.ApplyChangedToOpenFilesRequest>({
|
||||
command: ts.server.protocol.CommandTypes.ApplyChangedToOpenFiles,
|
||||
arguments: {
|
||||
openFiles: [{
|
||||
fileName: path,
|
||||
@@ -341,8 +343,8 @@ function setup(files: ts.projectSystem.File[]) {
|
||||
|
||||
function findAllReferences(file: string, line: number, offset: number) {
|
||||
ts.Debug.assertIsDefined(files.find(f => f.path === file));
|
||||
session.executeCommandSeq<ts.projectSystem.protocol.ReferencesRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.References,
|
||||
session.executeCommandSeq<ts.server.protocol.ReferencesRequest>({
|
||||
command: ts.server.protocol.CommandTypes.References,
|
||||
arguments: {
|
||||
file,
|
||||
line,
|
||||
|
||||
@@ -1,26 +1,28 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { createServerHost, File } from "../virtualFileSystemWithWatch";
|
||||
import { createSession, openFilesForSession, checkNumberOfInferredProjects } from "./helpers";
|
||||
|
||||
const aTs: ts.projectSystem.File = {
|
||||
const aTs: File = {
|
||||
path: "/a.ts",
|
||||
content: `import { B } from "./b";`
|
||||
};
|
||||
const bDts: ts.projectSystem.File = {
|
||||
const bDts: File = {
|
||||
path: "/b.d.ts",
|
||||
content: `export declare class B {}`
|
||||
};
|
||||
const bJs: ts.projectSystem.File = {
|
||||
const bJs: File = {
|
||||
path: "/b.js",
|
||||
content: `export class B {}`
|
||||
};
|
||||
describe("unittests:: tsserver:: auxiliaryProject", () => {
|
||||
it("AuxiliaryProject does not remove scrips from InferredProject", () => {
|
||||
const host = ts.projectSystem.createServerHost([aTs, bDts, bJs]);
|
||||
const session = ts.projectSystem.createSession(host);
|
||||
const host = createServerHost([aTs, bDts, bJs]);
|
||||
const session = createSession(host);
|
||||
const projectService = session.getProjectService();
|
||||
ts.projectSystem.openFilesForSession([aTs], session);
|
||||
openFilesForSession([aTs], session);
|
||||
|
||||
// Open file is in inferred project
|
||||
ts.projectSystem.checkNumberOfInferredProjects(projectService, 1);
|
||||
checkNumberOfInferredProjects(projectService, 1);
|
||||
const inferredProject = projectService.inferredProjects[0];
|
||||
|
||||
// getNoDtsResolutionProject will create an AuxiliaryProject with a.ts and b.js
|
||||
@@ -39,7 +41,7 @@ describe("unittests:: tsserver:: auxiliaryProject", () => {
|
||||
|
||||
// When b.js is opened in the editor, it should be put into an InferredProject
|
||||
// even though it's still contained by the AuxiliaryProject.
|
||||
ts.projectSystem.openFilesForSession([bJs], session);
|
||||
openFilesForSession([bJs], session);
|
||||
assert(!bJsScriptInfo.isOrphan());
|
||||
assert(bJsScriptInfo.isContainedByBackgroundProject());
|
||||
assert.equal(bJsScriptInfo.getDefaultProject().projectKind, ts.server.ProjectKind.Inferred);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { createServerHost, File, libFile, SymLink, TestServerHost } from "../virtualFileSystemWithWatch";
|
||||
import { Logger, createProjectService, createLoggerWithInMemoryLogs, baselineTsserverLogs, createSession, openFilesForSession, makeSessionRequest, checkProjectActualFiles, checkNumberOfProjects } from "./helpers";
|
||||
|
||||
describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectSystem CachingFileSystemInformation", () => {
|
||||
enum CalledMapsWithSingleArg {
|
||||
@@ -12,7 +14,7 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS
|
||||
}
|
||||
type CalledMaps = CalledMapsWithSingleArg | CalledMapsWithFiveArgs;
|
||||
type CalledWithFiveArgs = [readonly string[], readonly string[], readonly string[], number];
|
||||
function createLoggerTrackingHostCalls(host: ts.projectSystem.TestServerHost) {
|
||||
function createLoggerTrackingHostCalls(host: TestServerHost) {
|
||||
const calledMaps: Record<CalledMapsWithSingleArg, ts.MultiMap<string, true>> & Record<CalledMapsWithFiveArgs, ts.MultiMap<string, CalledWithFiveArgs>> = {
|
||||
fileExists: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.fileExists),
|
||||
directoryExists: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.directoryExists),
|
||||
@@ -43,13 +45,13 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS
|
||||
return calledMap;
|
||||
}
|
||||
|
||||
function logCacheEntry(logger: ts.projectSystem.Logger, callback: CalledMaps) {
|
||||
function logCacheEntry(logger: Logger, callback: CalledMaps) {
|
||||
const result = ts.arrayFrom<[string, (true | CalledWithFiveArgs)[]], { key: string, count: number }>(calledMaps[callback].entries(), ([key, arr]) => ({ key, count: arr.length }));
|
||||
logger.info(`${callback}:: ${JSON.stringify(result)}`);
|
||||
calledMaps[callback].clear();
|
||||
}
|
||||
|
||||
function logCacheAndClear(logger: ts.projectSystem.Logger) {
|
||||
function logCacheAndClear(logger: Logger) {
|
||||
logCacheEntry(logger, CalledMapsWithSingleArg.fileExists);
|
||||
logCacheEntry(logger, CalledMapsWithSingleArg.directoryExists);
|
||||
logCacheEntry(logger, CalledMapsWithSingleArg.getDirectories);
|
||||
@@ -58,7 +60,7 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS
|
||||
}
|
||||
}
|
||||
|
||||
function logSemanticDiagnostics(projectService: ts.server.ProjectService, project: ts.server.Project, file: ts.projectSystem.File) {
|
||||
function logSemanticDiagnostics(projectService: ts.server.ProjectService, project: ts.server.Project, file: File) {
|
||||
const diags = project.getLanguageService().getSemanticDiagnostics(file.path);
|
||||
projectService.logger.info(`getSemanticDiagnostics:: ${file.path}:: ${diags.length}`);
|
||||
diags.forEach(d => projectService.logger.info(ts.formatDiagnostic(d, project)));
|
||||
@@ -66,18 +68,18 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS
|
||||
|
||||
it("works using legacy resolution logic", () => {
|
||||
let rootContent = `import {x} from "f1"`;
|
||||
const root: ts.projectSystem.File = {
|
||||
const root: File = {
|
||||
path: "/c/d/f0.ts",
|
||||
content: rootContent
|
||||
};
|
||||
|
||||
const imported: ts.projectSystem.File = {
|
||||
const imported: File = {
|
||||
path: "/c/f1.ts",
|
||||
content: `foo()`
|
||||
};
|
||||
|
||||
const host = ts.projectSystem.createServerHost([root, imported]);
|
||||
const projectService = ts.projectSystem.createProjectService(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) });
|
||||
const host = createServerHost([root, imported]);
|
||||
const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) });
|
||||
projectService.setCompilerOptionsForInferredProjects({ module: ts.ModuleKind.AMD, noLib: true });
|
||||
projectService.openClientFile(root.path);
|
||||
const project = projectService.inferredProjects[0];
|
||||
@@ -115,7 +117,7 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS
|
||||
projectService.setCompilerOptionsForInferredProjects({ module: ts.ModuleKind.AMD, noLib: true, target: ts.ScriptTarget.ES5 });
|
||||
logSemanticDiagnostics(projectService, project, imported);
|
||||
logCacheAndClear(projectService.logger);
|
||||
ts.projectSystem.baselineTsserverLogs("cachingFileSystemInformation", "works using legacy resolution logic", projectService);
|
||||
baselineTsserverLogs("cachingFileSystemInformation", "works using legacy resolution logic", projectService);
|
||||
|
||||
function editContent(newContent: string) {
|
||||
rootScriptInfo.editContent(0, rootContent.length, newContent);
|
||||
@@ -124,18 +126,18 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS
|
||||
});
|
||||
|
||||
it("loads missing files from disk", () => {
|
||||
const root: ts.projectSystem.File = {
|
||||
const root: File = {
|
||||
path: "/c/foo.ts",
|
||||
content: `import {y} from "bar"`
|
||||
};
|
||||
|
||||
const imported: ts.projectSystem.File = {
|
||||
const imported: File = {
|
||||
path: "/c/bar.d.ts",
|
||||
content: `export var y = 1`
|
||||
};
|
||||
|
||||
const host = ts.projectSystem.createServerHost([root]);
|
||||
const projectService = ts.projectSystem.createProjectService(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) });
|
||||
const host = createServerHost([root]);
|
||||
const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) });
|
||||
projectService.setCompilerOptionsForInferredProjects({ module: ts.ModuleKind.AMD, noLib: true });
|
||||
const logCacheAndClear = createLoggerTrackingHostCalls(host);
|
||||
projectService.openClientFile(root.path);
|
||||
@@ -150,29 +152,29 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
logSemanticDiagnostics(projectService, project, root);
|
||||
logCacheAndClear(projectService.logger);
|
||||
ts.projectSystem.baselineTsserverLogs("cachingFileSystemInformation", "loads missing files from disk", projectService);
|
||||
baselineTsserverLogs("cachingFileSystemInformation", "loads missing files from disk", projectService);
|
||||
});
|
||||
|
||||
it("when calling goto definition of module", () => {
|
||||
const clientFile: ts.projectSystem.File = {
|
||||
const clientFile: File = {
|
||||
path: "/a/b/controllers/vessels/client.ts",
|
||||
content: `
|
||||
import { Vessel } from '~/models/vessel';
|
||||
const v = new Vessel();
|
||||
`
|
||||
};
|
||||
const anotherModuleFile: ts.projectSystem.File = {
|
||||
const anotherModuleFile: File = {
|
||||
path: "/a/b/utils/db.ts",
|
||||
content: "export class Bookshelf { }"
|
||||
};
|
||||
const moduleFile: ts.projectSystem.File = {
|
||||
const moduleFile: File = {
|
||||
path: "/a/b/models/vessel.ts",
|
||||
content: `
|
||||
import { Bookshelf } from '~/utils/db';
|
||||
export class Vessel extends Bookshelf {}
|
||||
`
|
||||
};
|
||||
const tsconfigFile: ts.projectSystem.File = {
|
||||
const tsconfigFile: File = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
@@ -195,13 +197,13 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS
|
||||
})
|
||||
};
|
||||
const projectFiles = [clientFile, anotherModuleFile, moduleFile, tsconfigFile];
|
||||
const host = ts.projectSystem.createServerHost(projectFiles);
|
||||
const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) });
|
||||
ts.projectSystem.openFilesForSession([clientFile], session);
|
||||
const host = createServerHost(projectFiles);
|
||||
const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) });
|
||||
openFilesForSession([clientFile], session);
|
||||
const logCacheAndClear = createLoggerTrackingHostCalls(host);
|
||||
|
||||
// Get definitions shouldnt make host requests
|
||||
const getDefinitionRequest = ts.projectSystem.makeSessionRequest<ts.projectSystem.protocol.FileLocationRequestArgs>(ts.projectSystem.protocol.CommandTypes.Definition, {
|
||||
const getDefinitionRequest = makeSessionRequest<ts.server.protocol.FileLocationRequestArgs>(ts.server.protocol.CommandTypes.Definition, {
|
||||
file: clientFile.path,
|
||||
position: clientFile.content.indexOf("/vessel") + 1,
|
||||
line: undefined!, // TODO: GH#18217
|
||||
@@ -211,35 +213,35 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS
|
||||
logCacheAndClear(session.logger);
|
||||
|
||||
// Open the file should call only file exists on module directory and use cached value for parental directory
|
||||
ts.projectSystem.openFilesForSession([moduleFile], session);
|
||||
openFilesForSession([moduleFile], session);
|
||||
logCacheAndClear(session.logger);
|
||||
|
||||
ts.projectSystem.baselineTsserverLogs("cachingFileSystemInformation", "when calling goto definition of module", session);
|
||||
baselineTsserverLogs("cachingFileSystemInformation", "when calling goto definition of module", session);
|
||||
});
|
||||
|
||||
describe("WatchDirectories for config file with", () => {
|
||||
function verifyWatchDirectoriesCaseSensitivity(useCaseSensitiveFileNames: boolean) {
|
||||
it(`watchDirectories for config file with case ${useCaseSensitiveFileNames ? "" : "in"}sensitive file system`, () => {
|
||||
const frontendDir = "/Users/someuser/work/applications/frontend";
|
||||
const file1: ts.projectSystem.File = {
|
||||
const file1: File = {
|
||||
path: `${frontendDir}/src/app/utils/Analytic.ts`,
|
||||
content: "export class SomeClass { };"
|
||||
};
|
||||
const file2: ts.projectSystem.File = {
|
||||
const file2: File = {
|
||||
path: `${frontendDir}/src/app/redux/configureStore.ts`,
|
||||
content: "export class configureStore { }"
|
||||
};
|
||||
const file3: ts.projectSystem.File = {
|
||||
const file3: File = {
|
||||
path: `${frontendDir}/src/app/utils/Cookie.ts`,
|
||||
content: "export class Cookie { }"
|
||||
};
|
||||
const es2016LibFile: ts.projectSystem.File = {
|
||||
const es2016LibFile: File = {
|
||||
path: "/a/lib/lib.es2016.full.d.ts",
|
||||
content: ts.projectSystem.libFile.content
|
||||
content: libFile.content
|
||||
};
|
||||
const typeRoots = ["types", "node_modules/@types"];
|
||||
const types = ["node", "jest"];
|
||||
const tsconfigFile: ts.projectSystem.File = {
|
||||
const tsconfigFile: File = {
|
||||
path: `${frontendDir}/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
@@ -273,8 +275,8 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS
|
||||
})
|
||||
};
|
||||
const projectFiles = [file1, file2, es2016LibFile, tsconfigFile];
|
||||
const host = ts.projectSystem.createServerHost(projectFiles, { useCaseSensitiveFileNames });
|
||||
const projectService = ts.projectSystem.createProjectService(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) });
|
||||
const host = createServerHost(projectFiles, { useCaseSensitiveFileNames });
|
||||
const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) });
|
||||
projectService.openClientFile(file1.path);
|
||||
|
||||
const logCacheAndClear = createLoggerTrackingHostCalls(host);
|
||||
@@ -286,7 +288,7 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS
|
||||
|
||||
projectService.openClientFile(file3.path);
|
||||
logCacheAndClear(projectService.logger);
|
||||
ts.projectSystem.baselineTsserverLogs("cachingFileSystemInformation", `watchDirectories for config file with case ${useCaseSensitiveFileNames ? "" : "in"}sensitive file system`, projectService);
|
||||
baselineTsserverLogs("cachingFileSystemInformation", `watchDirectories for config file with case ${useCaseSensitiveFileNames ? "" : "in"}sensitive file system`, projectService);
|
||||
});
|
||||
}
|
||||
verifyWatchDirectoriesCaseSensitivity(/*useCaseSensitiveFileNames*/ false);
|
||||
@@ -296,15 +298,15 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS
|
||||
describe("Subfolder invalidations correctly include parent folder failed lookup locations", () => {
|
||||
function runFailedLookupTest(resolution: "Node" | "Classic") {
|
||||
const projectLocation = "/proj";
|
||||
const file1: ts.projectSystem.File = {
|
||||
const file1: File = {
|
||||
path: `${projectLocation}/foo/boo/app.ts`,
|
||||
content: `import * as debug from "debug"`
|
||||
};
|
||||
const file2: ts.projectSystem.File = {
|
||||
const file2: File = {
|
||||
path: `${projectLocation}/foo/boo/moo/app.ts`,
|
||||
content: `import * as debug from "debug"`
|
||||
};
|
||||
const tsconfig: ts.projectSystem.File = {
|
||||
const tsconfig: File = {
|
||||
path: `${projectLocation}/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
files: ["foo/boo/app.ts", "foo/boo/moo/app.ts"],
|
||||
@@ -312,17 +314,17 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS
|
||||
})
|
||||
};
|
||||
|
||||
const files = [file1, file2, tsconfig, ts.projectSystem.libFile];
|
||||
const host = ts.projectSystem.createServerHost(files);
|
||||
const service = ts.projectSystem.createProjectService(host);
|
||||
const files = [file1, file2, tsconfig, libFile];
|
||||
const host = createServerHost(files);
|
||||
const service = createProjectService(host);
|
||||
service.openClientFile(file1.path);
|
||||
|
||||
const project = service.configuredProjects.get(tsconfig.path)!;
|
||||
ts.projectSystem.checkProjectActualFiles(project, files.map(f => f.path));
|
||||
checkProjectActualFiles(project, files.map(f => f.path));
|
||||
assert.deepEqual(project.getLanguageService().getSemanticDiagnostics(file1.path).map(diag => diag.messageText), ["Cannot find module 'debug' or its corresponding type declarations."]);
|
||||
assert.deepEqual(project.getLanguageService().getSemanticDiagnostics(file2.path).map(diag => diag.messageText), ["Cannot find module 'debug' or its corresponding type declarations."]);
|
||||
|
||||
const debugTypesFile: ts.projectSystem.File = {
|
||||
const debugTypesFile: File = {
|
||||
path: `${projectLocation}/node_modules/debug/index.d.ts`,
|
||||
content: "export {}"
|
||||
};
|
||||
@@ -330,7 +332,7 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS
|
||||
host.writeFile(debugTypesFile.path, debugTypesFile.content);
|
||||
host.runQueuedTimeoutCallbacks(); // Scheduled invalidation of resolutions
|
||||
host.runQueuedTimeoutCallbacks(); // Actual update
|
||||
ts.projectSystem.checkProjectActualFiles(project, files.map(f => f.path));
|
||||
checkProjectActualFiles(project, files.map(f => f.path));
|
||||
assert.deepEqual(project.getLanguageService().getSemanticDiagnostics(file1.path).map(diag => diag.messageText), []);
|
||||
assert.deepEqual(project.getLanguageService().getSemanticDiagnostics(file2.path).map(diag => diag.messageText), []);
|
||||
}
|
||||
@@ -346,19 +348,19 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS
|
||||
describe("Verify npm install in directory with tsconfig file works when", () => {
|
||||
function verifyNpmInstall(timeoutDuringPartialInstallation: boolean) {
|
||||
const root = "/user/username/rootfolder/otherfolder";
|
||||
const getRootedFileOrFolder = (fileOrFolder: ts.projectSystem.File) => {
|
||||
const getRootedFileOrFolder = (fileOrFolder: File) => {
|
||||
fileOrFolder.path = root + fileOrFolder.path;
|
||||
return fileOrFolder;
|
||||
};
|
||||
const app: ts.projectSystem.File = getRootedFileOrFolder({
|
||||
const app: File = getRootedFileOrFolder({
|
||||
path: "/a/b/app.ts",
|
||||
content: "import _ from 'lodash';"
|
||||
});
|
||||
const tsconfigJson: ts.projectSystem.File = getRootedFileOrFolder({
|
||||
const tsconfigJson: File = getRootedFileOrFolder({
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: '{ "compilerOptions": { } }'
|
||||
});
|
||||
const packageJson: ts.projectSystem.File = getRootedFileOrFolder({
|
||||
const packageJson: File = getRootedFileOrFolder({
|
||||
path: "/a/b/package.json",
|
||||
content: `
|
||||
{
|
||||
@@ -383,15 +385,15 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS
|
||||
}
|
||||
`
|
||||
});
|
||||
const host = ts.projectSystem.createServerHost([app, ts.projectSystem.libFile, tsconfigJson, packageJson]);
|
||||
const projectService = ts.projectSystem.createProjectService(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) });
|
||||
const host = createServerHost([app, libFile, tsconfigJson, packageJson]);
|
||||
const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) });
|
||||
projectService.setHostConfiguration({ preferences: { includePackageJsonAutoImports: "off" } });
|
||||
projectService.openClientFile(app.path);
|
||||
|
||||
let npmInstallComplete = false;
|
||||
|
||||
// Simulate npm install
|
||||
const filesAndFoldersToAdd: ts.projectSystem.File[] = [
|
||||
const filesAndFoldersToAdd: File[] = [
|
||||
{ path: "/a/b/node_modules" },
|
||||
{ path: "/a/b/node_modules/.staging/@types" },
|
||||
{ path: "/a/b/node_modules/.staging/lodash-b0733faa" },
|
||||
@@ -469,7 +471,7 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS
|
||||
npmInstallComplete = true;
|
||||
verifyAfterPartialOrCompleteNpmInstall(2);
|
||||
|
||||
ts.projectSystem.baselineTsserverLogs(
|
||||
baselineTsserverLogs(
|
||||
"cachingFileSystemInformation",
|
||||
`npm install works when ${timeoutDuringPartialInstallation ? "timeout occurs inbetween installation" : "timeout occurs after installation"}`,
|
||||
projectService
|
||||
@@ -503,25 +505,25 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS
|
||||
|
||||
it("when node_modules dont receive event for the @types file addition", () => {
|
||||
const projectLocation = "/user/username/folder/myproject";
|
||||
const app: ts.projectSystem.File = {
|
||||
const app: File = {
|
||||
path: `${projectLocation}/app.ts`,
|
||||
content: `import * as debug from "debug"`
|
||||
};
|
||||
const tsconfig: ts.projectSystem.File = {
|
||||
const tsconfig: File = {
|
||||
path: `${projectLocation}/tsconfig.json`,
|
||||
content: ""
|
||||
};
|
||||
|
||||
const files = [app, tsconfig, ts.projectSystem.libFile];
|
||||
const host = ts.projectSystem.createServerHost(files);
|
||||
const service = ts.projectSystem.createProjectService(host);
|
||||
const files = [app, tsconfig, libFile];
|
||||
const host = createServerHost(files);
|
||||
const service = createProjectService(host);
|
||||
service.openClientFile(app.path);
|
||||
|
||||
const project = service.configuredProjects.get(tsconfig.path)!;
|
||||
ts.projectSystem.checkProjectActualFiles(project, files.map(f => f.path));
|
||||
checkProjectActualFiles(project, files.map(f => f.path));
|
||||
assert.deepEqual(project.getLanguageService().getSemanticDiagnostics(app.path).map(diag => diag.messageText), ["Cannot find module 'debug' or its corresponding type declarations."]);
|
||||
|
||||
const debugTypesFile: ts.projectSystem.File = {
|
||||
const debugTypesFile: File = {
|
||||
path: `${projectLocation}/node_modules/@types/debug/index.d.ts`,
|
||||
content: "export {}"
|
||||
};
|
||||
@@ -535,25 +537,25 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS
|
||||
};
|
||||
host.writeFile(debugTypesFile.path, debugTypesFile.content);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
ts.projectSystem.checkProjectActualFiles(project, files.map(f => f.path));
|
||||
checkProjectActualFiles(project, files.map(f => f.path));
|
||||
assert.deepEqual(project.getLanguageService().getSemanticDiagnostics(app.path).map(diag => diag.messageText), []);
|
||||
});
|
||||
|
||||
it("when creating new file in symlinked folder", () => {
|
||||
const module1: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/client/folder1/module1.ts`,
|
||||
const module1: File = {
|
||||
path: `/user/username/projects/myproject/client/folder1/module1.ts`,
|
||||
content: `export class Module1Class { }`
|
||||
};
|
||||
const module2: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/folder2/module2.ts`,
|
||||
const module2: File = {
|
||||
path: `/user/username/projects/myproject/folder2/module2.ts`,
|
||||
content: `import * as M from "folder1/module1";`
|
||||
};
|
||||
const symlink: ts.projectSystem.SymLink = {
|
||||
path: `${ts.tscWatch.projectRoot}/client/linktofolder2`,
|
||||
symLink: `${ts.tscWatch.projectRoot}/folder2`,
|
||||
const symlink: SymLink = {
|
||||
path: `/user/username/projects/myproject/client/linktofolder2`,
|
||||
symLink: `/user/username/projects/myproject/folder2`,
|
||||
};
|
||||
const config: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const config: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
baseUrl: "client",
|
||||
@@ -562,15 +564,15 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS
|
||||
include: ["client/**/*", "folder2"]
|
||||
})
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([module1, module2, symlink, config, ts.projectSystem.libFile]);
|
||||
const service = ts.projectSystem.createProjectService(host);
|
||||
const host = createServerHost([module1, module2, symlink, config, libFile]);
|
||||
const service = createProjectService(host);
|
||||
service.openClientFile(`${symlink.path}/module2.ts`);
|
||||
ts.projectSystem.checkNumberOfProjects(service, { configuredProjects: 1 });
|
||||
checkNumberOfProjects(service, { configuredProjects: 1 });
|
||||
const project = ts.Debug.checkDefined(service.configuredProjects.get(config.path));
|
||||
ts.projectSystem.checkProjectActualFiles(project, [module1.path, `${symlink.path}/module2.ts`, config.path, ts.projectSystem.libFile.path]);
|
||||
checkProjectActualFiles(project, [module1.path, `${symlink.path}/module2.ts`, config.path, libFile.path]);
|
||||
host.writeFile(`${symlink.path}/module3.ts`, `import * as M from "folder1/module1";`);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
ts.projectSystem.checkNumberOfProjects(service, { configuredProjects: 1 });
|
||||
ts.projectSystem.checkProjectActualFiles(project, [module1.path, `${symlink.path}/module2.ts`, config.path, ts.projectSystem.libFile.path, `${symlink.path}/module3.ts`]);
|
||||
checkNumberOfProjects(service, { configuredProjects: 1 });
|
||||
checkProjectActualFiles(project, [module1.path, `${symlink.path}/module2.ts`, config.path, libFile.path, `${symlink.path}/module3.ts`]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { createServerHost } from "../virtualFileSystemWithWatch";
|
||||
import { createSession, TestServerCancellationToken } from "./helpers";
|
||||
|
||||
describe("unittests:: tsserver:: cancellationToken", () => {
|
||||
// Disable sourcemap support for the duration of the test, as sourcemapping the errors generated during this test is slow and not something we care to test
|
||||
@@ -17,7 +19,7 @@ describe("unittests:: tsserver:: cancellationToken", () => {
|
||||
path: "/a/b/app.ts",
|
||||
content: "let xyz = 1;"
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([f1]);
|
||||
const host = createServerHost([f1]);
|
||||
let expectedRequestId: number;
|
||||
const cancellationToken: ts.server.ServerCancellationToken = {
|
||||
isCancellationRequested: () => false,
|
||||
@@ -30,7 +32,7 @@ describe("unittests:: tsserver:: cancellationToken", () => {
|
||||
resetRequest: ts.noop
|
||||
};
|
||||
|
||||
const session = ts.projectSystem.createSession(host, { cancellationToken });
|
||||
const session = createSession(host, { cancellationToken });
|
||||
|
||||
expectedRequestId = session.getNextSeq();
|
||||
session.executeCommandSeq({
|
||||
@@ -68,9 +70,9 @@ describe("unittests:: tsserver:: cancellationToken", () => {
|
||||
})
|
||||
};
|
||||
|
||||
const cancellationToken = new ts.projectSystem.TestServerCancellationToken();
|
||||
const host = ts.projectSystem.createServerHost([f1, config]);
|
||||
const session = ts.projectSystem.createSession(host, {
|
||||
const cancellationToken = new TestServerCancellationToken();
|
||||
const host = createServerHost([f1, config]);
|
||||
const session = createSession(host, {
|
||||
canUseEvents: true,
|
||||
eventHandler: ts.noop,
|
||||
cancellationToken
|
||||
@@ -79,12 +81,12 @@ describe("unittests:: tsserver:: cancellationToken", () => {
|
||||
session.executeCommandSeq({
|
||||
command: "open",
|
||||
arguments: { file: f1.path }
|
||||
} as ts.projectSystem.protocol.OpenRequest);
|
||||
} as ts.server.protocol.OpenRequest);
|
||||
// send geterr for missing file
|
||||
session.executeCommandSeq({
|
||||
command: "geterr",
|
||||
arguments: { files: ["/a/missing"] }
|
||||
} as ts.projectSystem.protocol.GeterrRequest);
|
||||
} as ts.server.protocol.GeterrRequest);
|
||||
// Queued files
|
||||
assert.equal(host.getOutput().length, 0, "expected 0 message");
|
||||
host.checkTimeoutQueueLengthAndRun(1);
|
||||
@@ -98,7 +100,7 @@ describe("unittests:: tsserver:: cancellationToken", () => {
|
||||
session.executeCommandSeq({
|
||||
command: "geterr",
|
||||
arguments: { files: [f1.path] }
|
||||
} as ts.projectSystem.protocol.GeterrRequest);
|
||||
} as ts.server.protocol.GeterrRequest);
|
||||
|
||||
assert.equal(host.getOutput().length, 0, "expect 0 messages");
|
||||
|
||||
@@ -106,7 +108,7 @@ describe("unittests:: tsserver:: cancellationToken", () => {
|
||||
session.executeCommandSeq({
|
||||
command: "projectInfo",
|
||||
arguments: { file: f1.path }
|
||||
} as ts.projectSystem.protocol.ProjectInfoRequest);
|
||||
} as ts.server.protocol.ProjectInfoRequest);
|
||||
session.clearMessages();
|
||||
|
||||
// cancel previously issued Geterr
|
||||
@@ -123,13 +125,13 @@ describe("unittests:: tsserver:: cancellationToken", () => {
|
||||
session.executeCommandSeq({
|
||||
command: "geterr",
|
||||
arguments: { files: [f1.path] }
|
||||
} as ts.projectSystem.protocol.GeterrRequest);
|
||||
} as ts.server.protocol.GeterrRequest);
|
||||
assert.equal(host.getOutput().length, 0, "expect 0 messages");
|
||||
|
||||
// run first step
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
assert.equal(host.getOutput().length, 1, "expect 1 message");
|
||||
const e1 = getMessage(0) as ts.projectSystem.protocol.Event;
|
||||
const e1 = getMessage(0) as ts.server.protocol.Event;
|
||||
assert.equal(e1.event, "syntaxDiag");
|
||||
session.clearMessages();
|
||||
|
||||
@@ -145,26 +147,26 @@ describe("unittests:: tsserver:: cancellationToken", () => {
|
||||
session.executeCommandSeq({
|
||||
command: "geterr",
|
||||
arguments: { files: [f1.path] }
|
||||
} as ts.projectSystem.protocol.GeterrRequest);
|
||||
} as ts.server.protocol.GeterrRequest);
|
||||
assert.equal(host.getOutput().length, 0, "expect 0 messages");
|
||||
|
||||
// run first step
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
assert.equal(host.getOutput().length, 1, "expect 1 message");
|
||||
const e1 = getMessage(0) as ts.projectSystem.protocol.Event;
|
||||
const e1 = getMessage(0) as ts.server.protocol.Event;
|
||||
assert.equal(e1.event, "syntaxDiag");
|
||||
session.clearMessages();
|
||||
|
||||
// the semanticDiag message
|
||||
host.runQueuedImmediateCallbacks();
|
||||
assert.equal(host.getOutput().length, 1);
|
||||
const e2 = getMessage(0) as ts.projectSystem.protocol.Event;
|
||||
const e2 = getMessage(0) as ts.server.protocol.Event;
|
||||
assert.equal(e2.event, "semanticDiag");
|
||||
session.clearMessages();
|
||||
|
||||
host.runQueuedImmediateCallbacks(1);
|
||||
assert.equal(host.getOutput().length, 2);
|
||||
const e3 = getMessage(0) as ts.projectSystem.protocol.Event;
|
||||
const e3 = getMessage(0) as ts.server.protocol.Event;
|
||||
assert.equal(e3.event, "suggestionDiag");
|
||||
verifyRequestCompleted(getErrId, 1);
|
||||
|
||||
@@ -175,25 +177,25 @@ describe("unittests:: tsserver:: cancellationToken", () => {
|
||||
session.executeCommandSeq({
|
||||
command: "geterr",
|
||||
arguments: { files: [f1.path] }
|
||||
} as ts.projectSystem.protocol.GeterrRequest);
|
||||
} as ts.server.protocol.GeterrRequest);
|
||||
assert.equal(host.getOutput().length, 0, "expect 0 messages");
|
||||
// run first step
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
assert.equal(host.getOutput().length, 1, "expect 1 message");
|
||||
const e1 = getMessage(0) as ts.projectSystem.protocol.Event;
|
||||
const e1 = getMessage(0) as ts.server.protocol.Event;
|
||||
assert.equal(e1.event, "syntaxDiag");
|
||||
session.clearMessages();
|
||||
|
||||
session.executeCommandSeq({
|
||||
command: "geterr",
|
||||
arguments: { files: [f1.path] }
|
||||
} as ts.projectSystem.protocol.GeterrRequest);
|
||||
} as ts.server.protocol.GeterrRequest);
|
||||
// make sure that getErr1 is completed
|
||||
verifyRequestCompleted(getErr1, 0);
|
||||
}
|
||||
|
||||
function verifyRequestCompleted(expectedSeq: number, n: number) {
|
||||
const event = getMessage(n) as ts.projectSystem.protocol.RequestCompletedEvent;
|
||||
const event = getMessage(n) as ts.server.protocol.RequestCompletedEvent;
|
||||
assert.equal(event.event, "requestCompleted");
|
||||
assert.equal(event.body.request_seq, expectedSeq, "expectedSeq");
|
||||
session.clearMessages();
|
||||
@@ -215,9 +217,9 @@ describe("unittests:: tsserver:: cancellationToken", () => {
|
||||
compilerOptions: {}
|
||||
})
|
||||
};
|
||||
const cancellationToken = new ts.projectSystem.TestServerCancellationToken(/*cancelAfterRequest*/ 3);
|
||||
const host = ts.projectSystem.createServerHost([f1, config]);
|
||||
const session = ts.projectSystem.createSession(host, {
|
||||
const cancellationToken = new TestServerCancellationToken(/*cancelAfterRequest*/ 3);
|
||||
const host = createServerHost([f1, config]);
|
||||
const session = createSession(host, {
|
||||
canUseEvents: true,
|
||||
eventHandler: ts.noop,
|
||||
cancellationToken,
|
||||
@@ -227,31 +229,31 @@ describe("unittests:: tsserver:: cancellationToken", () => {
|
||||
session.executeCommandSeq({
|
||||
command: "open",
|
||||
arguments: { file: f1.path }
|
||||
} as ts.projectSystem.protocol.OpenRequest);
|
||||
} as ts.server.protocol.OpenRequest);
|
||||
|
||||
// send navbar request (normal priority)
|
||||
session.executeCommandSeq({
|
||||
command: "navbar",
|
||||
arguments: { file: f1.path }
|
||||
} as ts.projectSystem.protocol.NavBarRequest);
|
||||
} as ts.server.protocol.NavBarRequest);
|
||||
|
||||
// ensure the nav bar request can be canceled
|
||||
verifyExecuteCommandSeqIsCancellable({
|
||||
command: "navbar",
|
||||
arguments: { file: f1.path }
|
||||
} as ts.projectSystem.protocol.NavBarRequest);
|
||||
} as ts.server.protocol.NavBarRequest);
|
||||
|
||||
// send outlining spans request (normal priority)
|
||||
session.executeCommandSeq({
|
||||
command: "outliningSpans",
|
||||
arguments: { file: f1.path }
|
||||
} as ts.projectSystem.protocol.OutliningSpansRequestFull);
|
||||
} as ts.server.protocol.OutliningSpansRequestFull);
|
||||
|
||||
// ensure the outlining spans request can be canceled
|
||||
verifyExecuteCommandSeqIsCancellable({
|
||||
command: "outliningSpans",
|
||||
arguments: { file: f1.path }
|
||||
} as ts.projectSystem.protocol.OutliningSpansRequestFull);
|
||||
} as ts.server.protocol.OutliningSpansRequestFull);
|
||||
}
|
||||
|
||||
function verifyExecuteCommandSeqIsCancellable<T extends ts.server.protocol.Request>(request: Partial<T>) {
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { createServerHost, File, libFile } from "../virtualFileSystemWithWatch";
|
||||
import { TestTypingsInstaller, makeSessionRequest, createSession, openFilesForSession, checkNumberOfProjects, checkProjectRootFiles, createLoggerWithInMemoryLogs, baselineTsserverLogs, toExternalFiles, protocolTextSpanFromSubstring, TestSession } from "./helpers";
|
||||
|
||||
import CommandNames = ts.server.CommandNames;
|
||||
function createTestTypingsInstaller(host: ts.server.ServerHost) {
|
||||
return new ts.projectSystem.TestTypingsInstaller("/a/data/", /*throttleLimit*/5, host);
|
||||
return new TestTypingsInstaller("/a/data/", /*throttleLimit*/5, host);
|
||||
}
|
||||
|
||||
describe("unittests:: tsserver:: compileOnSave:: affected list", () => {
|
||||
function sendAffectedFileRequestAndCheckResult(session: ts.server.Session, request: ts.server.protocol.Request, expectedFileList: { projectFileName: string, files: ts.projectSystem.File[] }[]) {
|
||||
function sendAffectedFileRequestAndCheckResult(session: ts.server.Session, request: ts.server.protocol.Request, expectedFileList: { projectFileName: string, files: File[] }[]) {
|
||||
const response = session.executeCommand(request).response as ts.server.protocol.CompileOnSaveAffectedFileListSingleProject[];
|
||||
const actualResult = response.sort((list1, list2) => ts.compareStringsCaseSensitive(list1.projectFileName, list2.projectFileName));
|
||||
expectedFileList = expectedFileList.sort((list1, list2) => ts.compareStringsCaseSensitive(list1.projectFileName, list2.projectFileName));
|
||||
@@ -27,12 +28,12 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => {
|
||||
}
|
||||
|
||||
describe("for configured projects", () => {
|
||||
let moduleFile1: ts.projectSystem.File;
|
||||
let file1Consumer1: ts.projectSystem.File;
|
||||
let file1Consumer2: ts.projectSystem.File;
|
||||
let moduleFile2: ts.projectSystem.File;
|
||||
let globalFile3: ts.projectSystem.File;
|
||||
let configFile: ts.projectSystem.File;
|
||||
let moduleFile1: File;
|
||||
let file1Consumer1: File;
|
||||
let file1Consumer2: File;
|
||||
let moduleFile2: File;
|
||||
let globalFile3: File;
|
||||
let configFile: File;
|
||||
let changeModuleFile1ShapeRequest1: ts.server.protocol.Request;
|
||||
let changeModuleFile1InternalRequest1: ts.server.protocol.Request;
|
||||
// A compile on save affected file request using file1
|
||||
@@ -72,7 +73,7 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => {
|
||||
};
|
||||
|
||||
// Change the content of file1 to `export var T: number;export function Foo() { };`
|
||||
changeModuleFile1ShapeRequest1 = ts.projectSystem.makeSessionRequest<ts.server.protocol.ChangeRequestArgs>(CommandNames.Change, {
|
||||
changeModuleFile1ShapeRequest1 = makeSessionRequest<ts.server.protocol.ChangeRequestArgs>(ts.server.CommandNames.Change, {
|
||||
file: moduleFile1.path,
|
||||
line: 1,
|
||||
offset: 1,
|
||||
@@ -82,7 +83,7 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => {
|
||||
});
|
||||
|
||||
// Change the content of file1 to `export var T: number;export function Foo() { };`
|
||||
changeModuleFile1InternalRequest1 = ts.projectSystem.makeSessionRequest<ts.server.protocol.ChangeRequestArgs>(CommandNames.Change, {
|
||||
changeModuleFile1InternalRequest1 = makeSessionRequest<ts.server.protocol.ChangeRequestArgs>(ts.server.CommandNames.Change, {
|
||||
file: moduleFile1.path,
|
||||
line: 1,
|
||||
offset: 1,
|
||||
@@ -91,15 +92,15 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => {
|
||||
insertString: `var T1: number;`
|
||||
});
|
||||
|
||||
moduleFile1FileListRequest = ts.projectSystem.makeSessionRequest<ts.server.protocol.FileRequestArgs>(CommandNames.CompileOnSaveAffectedFileList, { file: moduleFile1.path, projectFileName: configFile.path });
|
||||
moduleFile1FileListRequest = makeSessionRequest<ts.server.protocol.FileRequestArgs>(ts.server.CommandNames.CompileOnSaveAffectedFileList, { file: moduleFile1.path, projectFileName: configFile.path });
|
||||
});
|
||||
|
||||
it("should contains only itself if a module file's shape didn't change, and all files referencing it if its shape changed", () => {
|
||||
const host = ts.projectSystem.createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, ts.projectSystem.libFile]);
|
||||
const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, libFile]);
|
||||
const typingsInstaller = createTestTypingsInstaller(host);
|
||||
const session = ts.projectSystem.createSession(host, { typingsInstaller });
|
||||
const session = createSession(host, { typingsInstaller });
|
||||
|
||||
ts.projectSystem.openFilesForSession([moduleFile1, file1Consumer1], session);
|
||||
openFilesForSession([moduleFile1, file1Consumer1], session);
|
||||
|
||||
// Send an initial compileOnSave request
|
||||
sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer2] }]);
|
||||
@@ -107,7 +108,7 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => {
|
||||
sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer2] }]);
|
||||
|
||||
// Change the content of file1 to `export var T: number;export function Foo() { console.log('hi'); };`
|
||||
const changeFile1InternalRequest = ts.projectSystem.makeSessionRequest<ts.server.protocol.ChangeRequestArgs>(CommandNames.Change, {
|
||||
const changeFile1InternalRequest = makeSessionRequest<ts.server.protocol.ChangeRequestArgs>(ts.server.CommandNames.Change, {
|
||||
file: moduleFile1.path,
|
||||
line: 1,
|
||||
offset: 46,
|
||||
@@ -120,17 +121,17 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => {
|
||||
});
|
||||
|
||||
it("should be up-to-date with the reference map changes", () => {
|
||||
const host = ts.projectSystem.createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, ts.projectSystem.libFile]);
|
||||
const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, libFile]);
|
||||
const typingsInstaller = createTestTypingsInstaller(host);
|
||||
const session = ts.projectSystem.createSession(host, { typingsInstaller });
|
||||
const session = createSession(host, { typingsInstaller });
|
||||
|
||||
ts.projectSystem.openFilesForSession([moduleFile1, file1Consumer1], session);
|
||||
openFilesForSession([moduleFile1, file1Consumer1], session);
|
||||
|
||||
// Send an initial compileOnSave request
|
||||
sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer2] }]);
|
||||
|
||||
// Change file2 content to `let y = Foo();`
|
||||
const removeFile1Consumer1ImportRequest = ts.projectSystem.makeSessionRequest<ts.server.protocol.ChangeRequestArgs>(CommandNames.Change, {
|
||||
const removeFile1Consumer1ImportRequest = makeSessionRequest<ts.server.protocol.ChangeRequestArgs>(ts.server.CommandNames.Change, {
|
||||
file: file1Consumer1.path,
|
||||
line: 1,
|
||||
offset: 1,
|
||||
@@ -143,7 +144,7 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => {
|
||||
sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer2] }]);
|
||||
|
||||
// Add the import statements back to file2
|
||||
const addFile2ImportRequest = ts.projectSystem.makeSessionRequest<ts.server.protocol.ChangeRequestArgs>(CommandNames.Change, {
|
||||
const addFile2ImportRequest = makeSessionRequest<ts.server.protocol.ChangeRequestArgs>(ts.server.CommandNames.Change, {
|
||||
file: file1Consumer1.path,
|
||||
line: 1,
|
||||
offset: 1,
|
||||
@@ -154,7 +155,7 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => {
|
||||
session.executeCommand(addFile2ImportRequest);
|
||||
|
||||
// Change the content of file1 to `export var T2: string;export var T: number;export function Foo() { };`
|
||||
const changeModuleFile1ShapeRequest2 = ts.projectSystem.makeSessionRequest<ts.server.protocol.ChangeRequestArgs>(CommandNames.Change, {
|
||||
const changeModuleFile1ShapeRequest2 = makeSessionRequest<ts.server.protocol.ChangeRequestArgs>(ts.server.CommandNames.Change, {
|
||||
file: moduleFile1.path,
|
||||
line: 1,
|
||||
offset: 1,
|
||||
@@ -167,11 +168,11 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => {
|
||||
});
|
||||
|
||||
it("should be up-to-date with changes made in non-open files", () => {
|
||||
const host = ts.projectSystem.createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, ts.projectSystem.libFile]);
|
||||
const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, libFile]);
|
||||
const typingsInstaller = createTestTypingsInstaller(host);
|
||||
const session = ts.projectSystem.createSession(host, { typingsInstaller });
|
||||
const session = createSession(host, { typingsInstaller });
|
||||
|
||||
ts.projectSystem.openFilesForSession([moduleFile1], session);
|
||||
openFilesForSession([moduleFile1], session);
|
||||
|
||||
// Send an initial compileOnSave request
|
||||
sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer2] }]);
|
||||
@@ -183,11 +184,11 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => {
|
||||
});
|
||||
|
||||
it("should be up-to-date with deleted files", () => {
|
||||
const host = ts.projectSystem.createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, ts.projectSystem.libFile]);
|
||||
const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, libFile]);
|
||||
const typingsInstaller = createTestTypingsInstaller(host);
|
||||
const session = ts.projectSystem.createSession(host, { typingsInstaller });
|
||||
const session = createSession(host, { typingsInstaller });
|
||||
|
||||
ts.projectSystem.openFilesForSession([moduleFile1], session);
|
||||
openFilesForSession([moduleFile1], session);
|
||||
sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer2] }]);
|
||||
|
||||
session.executeCommand(changeModuleFile1ShapeRequest1);
|
||||
@@ -197,14 +198,14 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => {
|
||||
});
|
||||
|
||||
it("should be up-to-date with newly created files", () => {
|
||||
const host = ts.projectSystem.createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, ts.projectSystem.libFile]);
|
||||
const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, libFile]);
|
||||
const typingsInstaller = createTestTypingsInstaller(host);
|
||||
const session = ts.projectSystem.createSession(host, { typingsInstaller });
|
||||
const session = createSession(host, { typingsInstaller });
|
||||
|
||||
ts.projectSystem.openFilesForSession([moduleFile1], session);
|
||||
openFilesForSession([moduleFile1], session);
|
||||
sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer2] }]);
|
||||
|
||||
const file1Consumer3: ts.projectSystem.File = {
|
||||
const file1Consumer3: File = {
|
||||
path: "/a/b/file1Consumer3.ts",
|
||||
content: `import {Foo} from "./moduleFile1"; let y = Foo();`
|
||||
};
|
||||
@@ -233,11 +234,11 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => {
|
||||
}`
|
||||
};
|
||||
|
||||
const host = ts.projectSystem.createServerHost([moduleFile1, file1Consumer1, configFile, ts.projectSystem.libFile]);
|
||||
const host = createServerHost([moduleFile1, file1Consumer1, configFile, libFile]);
|
||||
const typingsInstaller = createTestTypingsInstaller(host);
|
||||
const session = ts.projectSystem.createSession(host, { typingsInstaller });
|
||||
const session = createSession(host, { typingsInstaller });
|
||||
|
||||
ts.projectSystem.openFilesForSession([moduleFile1, file1Consumer1], session);
|
||||
openFilesForSession([moduleFile1, file1Consumer1], session);
|
||||
sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1] }]);
|
||||
|
||||
// change file1 shape now, and verify both files are affected
|
||||
@@ -250,12 +251,12 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => {
|
||||
});
|
||||
|
||||
it("should return all files if a global file changed shape", () => {
|
||||
const host = ts.projectSystem.createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, ts.projectSystem.libFile]);
|
||||
const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, libFile]);
|
||||
const typingsInstaller = createTestTypingsInstaller(host);
|
||||
const session = ts.projectSystem.createSession(host, { typingsInstaller });
|
||||
const session = createSession(host, { typingsInstaller });
|
||||
|
||||
ts.projectSystem.openFilesForSession([globalFile3], session);
|
||||
const changeGlobalFile3ShapeRequest = ts.projectSystem.makeSessionRequest<ts.server.protocol.ChangeRequestArgs>(CommandNames.Change, {
|
||||
openFilesForSession([globalFile3], session);
|
||||
const changeGlobalFile3ShapeRequest = makeSessionRequest<ts.server.protocol.ChangeRequestArgs>(ts.server.CommandNames.Change, {
|
||||
file: globalFile3.path,
|
||||
line: 1,
|
||||
offset: 1,
|
||||
@@ -266,7 +267,7 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => {
|
||||
|
||||
// check after file1 shape changes
|
||||
session.executeCommand(changeGlobalFile3ShapeRequest);
|
||||
const globalFile3FileListRequest = ts.projectSystem.makeSessionRequest<ts.server.protocol.FileRequestArgs>(CommandNames.CompileOnSaveAffectedFileList, { file: globalFile3.path });
|
||||
const globalFile3FileListRequest = makeSessionRequest<ts.server.protocol.FileRequestArgs>(ts.server.CommandNames.CompileOnSaveAffectedFileList, { file: globalFile3.path });
|
||||
sendAffectedFileRequestAndCheckResult(session, globalFile3FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2] }]);
|
||||
});
|
||||
|
||||
@@ -276,10 +277,10 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => {
|
||||
content: `{}`
|
||||
};
|
||||
|
||||
const host = ts.projectSystem.createServerHost([moduleFile1, file1Consumer1, file1Consumer2, configFile, ts.projectSystem.libFile]);
|
||||
const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, configFile, libFile]);
|
||||
const typingsInstaller = createTestTypingsInstaller(host);
|
||||
const session = ts.projectSystem.createSession(host, { typingsInstaller });
|
||||
ts.projectSystem.openFilesForSession([moduleFile1], session);
|
||||
const session = createSession(host, { typingsInstaller });
|
||||
openFilesForSession([moduleFile1], session);
|
||||
sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, []);
|
||||
});
|
||||
|
||||
@@ -294,10 +295,10 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => {
|
||||
}`
|
||||
};
|
||||
|
||||
const host = ts.projectSystem.createServerHost([moduleFile1, file1Consumer1, file1Consumer2, configFile, ts.projectSystem.libFile]);
|
||||
const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, configFile, libFile]);
|
||||
const typingsInstaller = createTestTypingsInstaller(host);
|
||||
const session = ts.projectSystem.createSession(host, { typingsInstaller });
|
||||
ts.projectSystem.openFilesForSession([moduleFile1], session);
|
||||
const session = createSession(host, { typingsInstaller });
|
||||
openFilesForSession([moduleFile1], session);
|
||||
sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, []);
|
||||
});
|
||||
|
||||
@@ -309,18 +310,18 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => {
|
||||
}`
|
||||
};
|
||||
|
||||
const configFile2: ts.projectSystem.File = {
|
||||
const configFile2: File = {
|
||||
path: "/a/tsconfig.json",
|
||||
content: `{
|
||||
"compileOnSave": true
|
||||
}`
|
||||
};
|
||||
|
||||
const host = ts.projectSystem.createServerHost([moduleFile1, file1Consumer1, file1Consumer2, configFile2, configFile, ts.projectSystem.libFile]);
|
||||
const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, configFile2, configFile, libFile]);
|
||||
const typingsInstaller = createTestTypingsInstaller(host);
|
||||
const session = ts.projectSystem.createSession(host, { typingsInstaller });
|
||||
const session = createSession(host, { typingsInstaller });
|
||||
|
||||
ts.projectSystem.openFilesForSession([moduleFile1, file1Consumer1], session);
|
||||
openFilesForSession([moduleFile1, file1Consumer1], session);
|
||||
sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer2] }]);
|
||||
});
|
||||
|
||||
@@ -335,12 +336,12 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => {
|
||||
}`
|
||||
};
|
||||
|
||||
const host = ts.projectSystem.createServerHost([moduleFile1, file1Consumer1, configFile, ts.projectSystem.libFile]);
|
||||
const host = createServerHost([moduleFile1, file1Consumer1, configFile, libFile]);
|
||||
const typingsInstaller = createTestTypingsInstaller(host);
|
||||
const session = ts.projectSystem.createSession(host, { typingsInstaller });
|
||||
ts.projectSystem.openFilesForSession([moduleFile1], session);
|
||||
const session = createSession(host, { typingsInstaller });
|
||||
openFilesForSession([moduleFile1], session);
|
||||
|
||||
const file1ChangeShapeRequest = ts.projectSystem.makeSessionRequest<ts.server.protocol.ChangeRequestArgs>(CommandNames.Change, {
|
||||
const file1ChangeShapeRequest = makeSessionRequest<ts.server.protocol.ChangeRequestArgs>(ts.server.CommandNames.Change, {
|
||||
file: moduleFile1.path,
|
||||
line: 1,
|
||||
offset: 27,
|
||||
@@ -364,12 +365,12 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => {
|
||||
}`
|
||||
};
|
||||
|
||||
const host = ts.projectSystem.createServerHost([moduleFile1, file1Consumer1, configFile, ts.projectSystem.libFile]);
|
||||
const host = createServerHost([moduleFile1, file1Consumer1, configFile, libFile]);
|
||||
const typingsInstaller = createTestTypingsInstaller(host);
|
||||
const session = ts.projectSystem.createSession(host, { typingsInstaller });
|
||||
ts.projectSystem.openFilesForSession([moduleFile1], session);
|
||||
const session = createSession(host, { typingsInstaller });
|
||||
openFilesForSession([moduleFile1], session);
|
||||
|
||||
const file1ChangeShapeRequest = ts.projectSystem.makeSessionRequest<ts.server.protocol.ChangeRequestArgs>(CommandNames.Change, {
|
||||
const file1ChangeShapeRequest = makeSessionRequest<ts.server.protocol.ChangeRequestArgs>(ts.server.CommandNames.Change, {
|
||||
file: moduleFile1.path,
|
||||
line: 1,
|
||||
offset: 27,
|
||||
@@ -382,18 +383,18 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => {
|
||||
});
|
||||
|
||||
it("should return cascaded affected file list", () => {
|
||||
const file1Consumer1Consumer1: ts.projectSystem.File = {
|
||||
const file1Consumer1Consumer1: File = {
|
||||
path: "/a/b/file1Consumer1Consumer1.ts",
|
||||
content: `import {y} from "./file1Consumer1";`
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([moduleFile1, file1Consumer1, file1Consumer1Consumer1, globalFile3, configFile, ts.projectSystem.libFile]);
|
||||
const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer1Consumer1, globalFile3, configFile, libFile]);
|
||||
const typingsInstaller = createTestTypingsInstaller(host);
|
||||
const session = ts.projectSystem.createSession(host, { typingsInstaller });
|
||||
const session = createSession(host, { typingsInstaller });
|
||||
|
||||
ts.projectSystem.openFilesForSession([moduleFile1, file1Consumer1], session);
|
||||
openFilesForSession([moduleFile1, file1Consumer1], session);
|
||||
sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer1Consumer1] }]);
|
||||
|
||||
const changeFile1Consumer1ShapeRequest = ts.projectSystem.makeSessionRequest<ts.server.protocol.ChangeRequestArgs>(CommandNames.Change, {
|
||||
const changeFile1Consumer1ShapeRequest = makeSessionRequest<ts.server.protocol.ChangeRequestArgs>(ts.server.CommandNames.Change, {
|
||||
file: file1Consumer1.path,
|
||||
line: 2,
|
||||
offset: 1,
|
||||
@@ -407,39 +408,39 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => {
|
||||
});
|
||||
|
||||
it("should work fine for files with circular references", () => {
|
||||
const file1: ts.projectSystem.File = {
|
||||
const file1: File = {
|
||||
path: "/a/b/file1.ts",
|
||||
content: `
|
||||
/// <reference path="./file2.ts" />
|
||||
export var t1 = 10;`
|
||||
};
|
||||
const file2: ts.projectSystem.File = {
|
||||
const file2: File = {
|
||||
path: "/a/b/file2.ts",
|
||||
content: `
|
||||
/// <reference path="./file1.ts" />
|
||||
export var t2 = 10;`
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([file1, file2, configFile]);
|
||||
const host = createServerHost([file1, file2, configFile]);
|
||||
const typingsInstaller = createTestTypingsInstaller(host);
|
||||
const session = ts.projectSystem.createSession(host, { typingsInstaller });
|
||||
const session = createSession(host, { typingsInstaller });
|
||||
|
||||
ts.projectSystem.openFilesForSession([file1, file2], session);
|
||||
const file1AffectedListRequest = ts.projectSystem.makeSessionRequest<ts.server.protocol.FileRequestArgs>(CommandNames.CompileOnSaveAffectedFileList, { file: file1.path });
|
||||
openFilesForSession([file1, file2], session);
|
||||
const file1AffectedListRequest = makeSessionRequest<ts.server.protocol.FileRequestArgs>(ts.server.CommandNames.CompileOnSaveAffectedFileList, { file: file1.path });
|
||||
sendAffectedFileRequestAndCheckResult(session, file1AffectedListRequest, [{ projectFileName: configFile.path, files: [file1, file2] }]);
|
||||
});
|
||||
|
||||
it("should return results for all projects if not specifying projectFileName", () => {
|
||||
const file1: ts.projectSystem.File = { path: "/a/b/file1.ts", content: "export var t = 10;" };
|
||||
const file2: ts.projectSystem.File = { path: "/a/b/file2.ts", content: `import {t} from "./file1"; var t2 = 11;` };
|
||||
const file3: ts.projectSystem.File = { path: "/a/c/file2.ts", content: `import {t} from "../b/file1"; var t3 = 11;` };
|
||||
const configFile1: ts.projectSystem.File = { path: "/a/b/tsconfig.json", content: `{ "compileOnSave": true }` };
|
||||
const configFile2: ts.projectSystem.File = { path: "/a/c/tsconfig.json", content: `{ "compileOnSave": true }` };
|
||||
const file1: File = { path: "/a/b/file1.ts", content: "export var t = 10;" };
|
||||
const file2: File = { path: "/a/b/file2.ts", content: `import {t} from "./file1"; var t2 = 11;` };
|
||||
const file3: File = { path: "/a/c/file2.ts", content: `import {t} from "../b/file1"; var t3 = 11;` };
|
||||
const configFile1: File = { path: "/a/b/tsconfig.json", content: `{ "compileOnSave": true }` };
|
||||
const configFile2: File = { path: "/a/c/tsconfig.json", content: `{ "compileOnSave": true }` };
|
||||
|
||||
const host = ts.projectSystem.createServerHost([file1, file2, file3, configFile1, configFile2]);
|
||||
const session = ts.projectSystem.createSession(host);
|
||||
const host = createServerHost([file1, file2, file3, configFile1, configFile2]);
|
||||
const session = createSession(host);
|
||||
|
||||
ts.projectSystem.openFilesForSession([file1, file2, file3], session);
|
||||
const file1AffectedListRequest = ts.projectSystem.makeSessionRequest<ts.server.protocol.FileRequestArgs>(CommandNames.CompileOnSaveAffectedFileList, { file: file1.path });
|
||||
openFilesForSession([file1, file2, file3], session);
|
||||
const file1AffectedListRequest = makeSessionRequest<ts.server.protocol.FileRequestArgs>(ts.server.CommandNames.CompileOnSaveAffectedFileList, { file: file1.path });
|
||||
|
||||
sendAffectedFileRequestAndCheckResult(session, file1AffectedListRequest, [
|
||||
{ projectFileName: configFile1.path, files: [file1, file2] },
|
||||
@@ -448,38 +449,38 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => {
|
||||
});
|
||||
|
||||
it("should detect removed code file", () => {
|
||||
const referenceFile1: ts.projectSystem.File = {
|
||||
const referenceFile1: File = {
|
||||
path: "/a/b/referenceFile1.ts",
|
||||
content: `
|
||||
/// <reference path="./moduleFile1.ts" />
|
||||
export var x = Foo();`
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([moduleFile1, referenceFile1, configFile]);
|
||||
const session = ts.projectSystem.createSession(host);
|
||||
const host = createServerHost([moduleFile1, referenceFile1, configFile]);
|
||||
const session = createSession(host);
|
||||
|
||||
ts.projectSystem.openFilesForSession([referenceFile1], session);
|
||||
openFilesForSession([referenceFile1], session);
|
||||
host.deleteFile(moduleFile1.path);
|
||||
|
||||
const request = ts.projectSystem.makeSessionRequest<ts.server.protocol.FileRequestArgs>(CommandNames.CompileOnSaveAffectedFileList, { file: referenceFile1.path });
|
||||
const request = makeSessionRequest<ts.server.protocol.FileRequestArgs>(ts.server.CommandNames.CompileOnSaveAffectedFileList, { file: referenceFile1.path });
|
||||
sendAffectedFileRequestAndCheckResult(session, request, [
|
||||
{ projectFileName: configFile.path, files: [referenceFile1] }
|
||||
]);
|
||||
const requestForMissingFile = ts.projectSystem.makeSessionRequest<ts.server.protocol.FileRequestArgs>(CommandNames.CompileOnSaveAffectedFileList, { file: moduleFile1.path });
|
||||
const requestForMissingFile = makeSessionRequest<ts.server.protocol.FileRequestArgs>(ts.server.CommandNames.CompileOnSaveAffectedFileList, { file: moduleFile1.path });
|
||||
sendAffectedFileRequestAndCheckResult(session, requestForMissingFile, []);
|
||||
});
|
||||
|
||||
it("should detect non-existing code file", () => {
|
||||
const referenceFile1: ts.projectSystem.File = {
|
||||
const referenceFile1: File = {
|
||||
path: "/a/b/referenceFile1.ts",
|
||||
content: `
|
||||
/// <reference path="./moduleFile2.ts" />
|
||||
export var x = Foo();`
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([referenceFile1, configFile]);
|
||||
const session = ts.projectSystem.createSession(host);
|
||||
const host = createServerHost([referenceFile1, configFile]);
|
||||
const session = createSession(host);
|
||||
|
||||
ts.projectSystem.openFilesForSession([referenceFile1], session);
|
||||
const request = ts.projectSystem.makeSessionRequest<ts.server.protocol.FileRequestArgs>(CommandNames.CompileOnSaveAffectedFileList, { file: referenceFile1.path });
|
||||
openFilesForSession([referenceFile1], session);
|
||||
const request = makeSessionRequest<ts.server.protocol.FileRequestArgs>(ts.server.CommandNames.CompileOnSaveAffectedFileList, { file: referenceFile1.path });
|
||||
sendAffectedFileRequestAndCheckResult(session, request, [
|
||||
{ projectFileName: configFile.path, files: [referenceFile1] }
|
||||
]);
|
||||
@@ -503,37 +504,37 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => {
|
||||
compileOnSave: true
|
||||
})
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([dtsFile, f2, config]);
|
||||
const session = ts.projectSystem.createSession(host);
|
||||
const host = createServerHost([dtsFile, f2, config]);
|
||||
const session = createSession(host);
|
||||
session.executeCommand({
|
||||
seq: 1,
|
||||
type: "request",
|
||||
command: "open",
|
||||
arguments: { file: dtsFile.path }
|
||||
} as ts.projectSystem.protocol.OpenRequest);
|
||||
} as ts.server.protocol.OpenRequest);
|
||||
const projectService = session.getProjectService();
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
const project = projectService.configuredProjects.get(config.path)!;
|
||||
ts.projectSystem.checkProjectRootFiles(project, [dtsFile.path, f2.path]);
|
||||
checkProjectRootFiles(project, [dtsFile.path, f2.path]);
|
||||
session.executeCommand({
|
||||
seq: 2,
|
||||
type: "request",
|
||||
command: "open",
|
||||
arguments: { file: f2.path }
|
||||
} as ts.projectSystem.protocol.OpenRequest);
|
||||
ts.projectSystem.checkNumberOfProjects(session.getProjectService(), { configuredProjects: 1 });
|
||||
} as ts.server.protocol.OpenRequest);
|
||||
checkNumberOfProjects(session.getProjectService(), { configuredProjects: 1 });
|
||||
const { response } = session.executeCommand({
|
||||
seq: 3,
|
||||
type: "request",
|
||||
command: "compileOnSaveAffectedFileList",
|
||||
arguments: { file: dtsFile.path }
|
||||
} as ts.projectSystem.protocol.CompileOnSaveAffectedFileListRequest);
|
||||
} as ts.server.protocol.CompileOnSaveAffectedFileListRequest);
|
||||
if (expectDTSEmit) {
|
||||
assert.equal((response as ts.projectSystem.protocol.CompileOnSaveAffectedFileListSingleProject[]).length, 1, "expected output from 1 project");
|
||||
assert.equal((response as ts.projectSystem.protocol.CompileOnSaveAffectedFileListSingleProject[])[0].fileNames.length, 2, "expected to affect 2 files");
|
||||
assert.equal((response as ts.server.protocol.CompileOnSaveAffectedFileListSingleProject[]).length, 1, "expected output from 1 project");
|
||||
assert.equal((response as ts.server.protocol.CompileOnSaveAffectedFileListSingleProject[])[0].fileNames.length, 2, "expected to affect 2 files");
|
||||
}
|
||||
else {
|
||||
assert.equal((response as ts.projectSystem.protocol.CompileOnSaveAffectedFileListSingleProject[]).length, 0, "expected no output");
|
||||
assert.equal((response as ts.server.protocol.CompileOnSaveAffectedFileListSingleProject[]).length, 0, "expected no output");
|
||||
}
|
||||
|
||||
|
||||
@@ -542,8 +543,8 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => {
|
||||
type: "request",
|
||||
command: "compileOnSaveAffectedFileList",
|
||||
arguments: { file: f2.path }
|
||||
} as ts.projectSystem.protocol.CompileOnSaveAffectedFileListRequest);
|
||||
assert.equal((response2 as ts.projectSystem.protocol.CompileOnSaveAffectedFileListSingleProject[]).length, 1, "expected output from 1 project");
|
||||
} as ts.server.protocol.CompileOnSaveAffectedFileListRequest);
|
||||
assert.equal((response2 as ts.server.protocol.CompileOnSaveAffectedFileListSingleProject[]).length, 1, "expected output from 1 project");
|
||||
}
|
||||
|
||||
it("should return empty array if change is made in a global declaration file", () => {
|
||||
@@ -610,14 +611,14 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => {
|
||||
compileOnSave: true
|
||||
})
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([f1, f2, config]);
|
||||
const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) });
|
||||
ts.projectSystem.openFilesForSession([f1], session);
|
||||
session.executeCommandSeq<ts.projectSystem.protocol.CompileOnSaveAffectedFileListRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList,
|
||||
const host = createServerHost([f1, f2, config]);
|
||||
const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) });
|
||||
openFilesForSession([f1], session);
|
||||
session.executeCommandSeq<ts.server.protocol.CompileOnSaveAffectedFileListRequest>({
|
||||
command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList,
|
||||
arguments: { file: f1.path }
|
||||
});
|
||||
ts.projectSystem.baselineTsserverLogs("compileOnSave", subScenario, session);
|
||||
baselineTsserverLogs("compileOnSave", subScenario, session);
|
||||
});
|
||||
}
|
||||
test("compileOnSaveAffectedFileList projectUsesOutFile should not be returned if not set", {});
|
||||
@@ -638,8 +639,8 @@ describe("unittests:: tsserver:: compileOnSave:: EmitFile test", () => {
|
||||
path: path + ts.Extension.Ts,
|
||||
content: lines.join(newLine)
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([f], { newLine });
|
||||
const session = ts.projectSystem.createSession(host);
|
||||
const host = createServerHost([f], { newLine });
|
||||
const session = createSession(host);
|
||||
const openRequest: ts.server.protocol.OpenRequest = {
|
||||
seq: 1,
|
||||
type: "request",
|
||||
@@ -672,12 +673,12 @@ describe("unittests:: tsserver:: compileOnSave:: EmitFile test", () => {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: `{}`
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([file1, file2, configFile, ts.projectSystem.libFile], { newLine: "\r\n" });
|
||||
const host = createServerHost([file1, file2, configFile, libFile], { newLine: "\r\n" });
|
||||
const typingsInstaller = createTestTypingsInstaller(host);
|
||||
const session = ts.projectSystem.createSession(host, { typingsInstaller });
|
||||
const session = createSession(host, { typingsInstaller });
|
||||
|
||||
ts.projectSystem.openFilesForSession([file1, file2], session);
|
||||
const compileFileRequest = ts.projectSystem.makeSessionRequest<ts.server.protocol.CompileOnSaveEmitFileRequestArgs>(CommandNames.CompileOnSaveEmitFile, { file: file1.path, projectFileName: configFile.path });
|
||||
openFilesForSession([file1, file2], session);
|
||||
const compileFileRequest = makeSessionRequest<ts.server.protocol.CompileOnSaveEmitFileRequestArgs>(ts.server.CommandNames.CompileOnSaveEmitFile, { file: file1.path, projectFileName: configFile.path });
|
||||
session.executeCommand(compileFileRequest);
|
||||
|
||||
const expectedEmittedFileName = "/a/b/f1.js";
|
||||
@@ -700,12 +701,12 @@ describe("unittests:: tsserver:: compileOnSave:: EmitFile test", () => {
|
||||
content: "console.log('file3');"
|
||||
};
|
||||
const externalProjectName = "/a/b/externalproject";
|
||||
const host = ts.projectSystem.createServerHost([file1, file2, file3, ts.projectSystem.libFile]);
|
||||
const session = ts.projectSystem.createSession(host);
|
||||
const host = createServerHost([file1, file2, file3, libFile]);
|
||||
const session = createSession(host);
|
||||
const projectService = session.getProjectService();
|
||||
|
||||
projectService.openExternalProject({
|
||||
rootFiles: ts.projectSystem.toExternalFiles([file1.path, file2.path]),
|
||||
rootFiles: toExternalFiles([file1.path, file2.path]),
|
||||
options: {
|
||||
allowJs: true,
|
||||
outFile: "dist.js",
|
||||
@@ -714,7 +715,7 @@ describe("unittests:: tsserver:: compileOnSave:: EmitFile test", () => {
|
||||
projectFileName: externalProjectName
|
||||
});
|
||||
|
||||
const emitRequest = ts.projectSystem.makeSessionRequest<ts.server.protocol.CompileOnSaveEmitFileRequestArgs>(CommandNames.CompileOnSaveEmitFile, { file: file1.path });
|
||||
const emitRequest = makeSessionRequest<ts.server.protocol.CompileOnSaveEmitFileRequestArgs>(ts.server.CommandNames.CompileOnSaveEmitFile, { file: file1.path });
|
||||
session.executeCommand(emitRequest);
|
||||
|
||||
const expectedOutFileName = "/a/b/dist.js";
|
||||
@@ -732,13 +733,13 @@ describe("unittests:: tsserver:: compileOnSave:: EmitFile test", () => {
|
||||
content: "consonle.log('file1');"
|
||||
};
|
||||
const externalProjectName = "/root/TypeScriptProject3/TypeScriptProject3/TypeScriptProject3.csproj";
|
||||
const host = ts.projectSystem.createServerHost([file1, ts.projectSystem.libFile]);
|
||||
const session = ts.projectSystem.createSession(host);
|
||||
const host = createServerHost([file1, libFile]);
|
||||
const session = createSession(host);
|
||||
const projectService = session.getProjectService();
|
||||
|
||||
const outFileName = "bar.js";
|
||||
projectService.openExternalProject({
|
||||
rootFiles: ts.projectSystem.toExternalFiles([file1.path]),
|
||||
rootFiles: toExternalFiles([file1.path]),
|
||||
options: {
|
||||
outFile: outFileName,
|
||||
sourceMap: true,
|
||||
@@ -747,7 +748,7 @@ describe("unittests:: tsserver:: compileOnSave:: EmitFile test", () => {
|
||||
projectFileName: externalProjectName
|
||||
});
|
||||
|
||||
const emitRequest = ts.projectSystem.makeSessionRequest<ts.server.protocol.CompileOnSaveEmitFileRequestArgs>(CommandNames.CompileOnSaveEmitFile, { file: file1.path });
|
||||
const emitRequest = makeSessionRequest<ts.server.protocol.CompileOnSaveEmitFileRequestArgs>(ts.server.CommandNames.CompileOnSaveEmitFile, { file: file1.path });
|
||||
session.executeCommand(emitRequest);
|
||||
|
||||
// Verify js file
|
||||
@@ -780,8 +781,8 @@ describe("unittests:: tsserver:: compileOnSave:: EmitFile test", () => {
|
||||
});
|
||||
|
||||
function verify(richResponse: boolean | undefined) {
|
||||
const config: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const config: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compileOnSave: true,
|
||||
compilerOptions: {
|
||||
@@ -792,27 +793,27 @@ describe("unittests:: tsserver:: compileOnSave:: EmitFile test", () => {
|
||||
exclude: ["node_modules"]
|
||||
})
|
||||
};
|
||||
const file1: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/file1.ts`,
|
||||
const file1: File = {
|
||||
path: `/user/username/projects/myproject/file1.ts`,
|
||||
content: "const x = 1;"
|
||||
};
|
||||
const file2: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/file2.ts`,
|
||||
const file2: File = {
|
||||
path: `/user/username/projects/myproject/file2.ts`,
|
||||
content: "const y = 2;"
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([file1, file2, config, ts.projectSystem.libFile]);
|
||||
const session = ts.projectSystem.createSession(host);
|
||||
ts.projectSystem.openFilesForSession([file1], session);
|
||||
const host = createServerHost([file1, file2, config, libFile]);
|
||||
const session = createSession(host);
|
||||
openFilesForSession([file1], session);
|
||||
|
||||
const affectedFileResponse = session.executeCommandSeq<ts.projectSystem.protocol.CompileOnSaveAffectedFileListRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList,
|
||||
const affectedFileResponse = session.executeCommandSeq<ts.server.protocol.CompileOnSaveAffectedFileListRequest>({
|
||||
command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList,
|
||||
arguments: { file: file1.path }
|
||||
}).response as ts.projectSystem.protocol.CompileOnSaveAffectedFileListSingleProject[];
|
||||
}).response as ts.server.protocol.CompileOnSaveAffectedFileListSingleProject[];
|
||||
assert.deepEqual(affectedFileResponse, [
|
||||
{ fileNames: [file1.path, file2.path], projectFileName: config.path, projectUsesOutFile: false }
|
||||
]);
|
||||
const file1SaveResponse = session.executeCommandSeq<ts.projectSystem.protocol.CompileOnSaveEmitFileRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile,
|
||||
const file1SaveResponse = session.executeCommandSeq<ts.server.protocol.CompileOnSaveEmitFileRequest>({
|
||||
command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile,
|
||||
arguments: { file: file1.path, richResponse }
|
||||
}).response;
|
||||
if (richResponse) {
|
||||
@@ -821,9 +822,9 @@ describe("unittests:: tsserver:: compileOnSave:: EmitFile test", () => {
|
||||
else {
|
||||
assert.isTrue(file1SaveResponse);
|
||||
}
|
||||
assert.strictEqual(host.readFile(`${ts.tscWatch.projectRoot}/test/file1.d.ts`), "declare const x = 1;\n");
|
||||
const file2SaveResponse = session.executeCommandSeq<ts.projectSystem.protocol.CompileOnSaveEmitFileRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile,
|
||||
assert.strictEqual(host.readFile(`/user/username/projects/myproject/test/file1.d.ts`), "declare const x = 1;\n");
|
||||
const file2SaveResponse = session.executeCommandSeq<ts.server.protocol.CompileOnSaveEmitFileRequest>({
|
||||
command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile,
|
||||
arguments: { file: file2.path, richResponse }
|
||||
}).response;
|
||||
if (richResponse) {
|
||||
@@ -833,7 +834,7 @@ describe("unittests:: tsserver:: compileOnSave:: EmitFile test", () => {
|
||||
start: undefined,
|
||||
end: undefined,
|
||||
fileName: undefined,
|
||||
text: ts.formatStringFromArgs(ts.Diagnostics.Cannot_write_file_0_because_it_would_overwrite_input_file.message, [`${ts.tscWatch.projectRoot}/test/file1.d.ts`]),
|
||||
text: ts.formatStringFromArgs(ts.Diagnostics.Cannot_write_file_0_because_it_would_overwrite_input_file.message, [`/user/username/projects/myproject/test/file1.d.ts`]),
|
||||
code: ts.Diagnostics.Cannot_write_file_0_because_it_would_overwrite_input_file.code,
|
||||
category: ts.diagnosticCategoryName(ts.Diagnostics.Cannot_write_file_0_because_it_would_overwrite_input_file),
|
||||
reportsUnnecessary: undefined,
|
||||
@@ -846,7 +847,7 @@ describe("unittests:: tsserver:: compileOnSave:: EmitFile test", () => {
|
||||
else {
|
||||
assert.isFalse(file2SaveResponse);
|
||||
}
|
||||
assert.isFalse(host.fileExists(`${ts.tscWatch.projectRoot}/test/file2.d.ts`));
|
||||
assert.isFalse(host.fileExists(`/user/username/projects/myproject/test/file2.d.ts`));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -867,9 +868,9 @@ describe("unittests:: tsserver:: compileOnSave:: EmitFile test", () => {
|
||||
verifyGlobalSave(/*declaration*/ false, /*hasModule*/ false);
|
||||
});
|
||||
});
|
||||
function verifyGlobalSave(declaration: boolean,hasModule: boolean) {
|
||||
const config: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
function verifyGlobalSave(declaration: boolean, hasModule: boolean) {
|
||||
const config: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compileOnSave: true,
|
||||
compilerOptions: {
|
||||
@@ -878,37 +879,37 @@ describe("unittests:: tsserver:: compileOnSave:: EmitFile test", () => {
|
||||
},
|
||||
})
|
||||
};
|
||||
const file1: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/file1.ts`,
|
||||
const file1: File = {
|
||||
path: `/user/username/projects/myproject/file1.ts`,
|
||||
content: `const x = 1;
|
||||
function foo() {
|
||||
return "hello";
|
||||
}`
|
||||
};
|
||||
const file2: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/file2.ts`,
|
||||
const file2: File = {
|
||||
path: `/user/username/projects/myproject/file2.ts`,
|
||||
content: `const y = 2;
|
||||
function bar() {
|
||||
return "world";
|
||||
}`
|
||||
};
|
||||
const file3: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/file3.ts`,
|
||||
const file3: File = {
|
||||
path: `/user/username/projects/myproject/file3.ts`,
|
||||
content: "const xy = 3;"
|
||||
};
|
||||
const module: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/module.ts`,
|
||||
const module: File = {
|
||||
path: `/user/username/projects/myproject/module.ts`,
|
||||
content: "export const xyz = 4;"
|
||||
};
|
||||
const files = [file1, file2, file3, ...(hasModule ? [module] : ts.emptyArray)];
|
||||
const host = ts.projectSystem.createServerHost([...files, config, ts.projectSystem.libFile]);
|
||||
const session = ts.projectSystem.createSession(host);
|
||||
ts.projectSystem.openFilesForSession([file1, file2], session);
|
||||
const host = createServerHost([...files, config, libFile]);
|
||||
const session = createSession(host);
|
||||
openFilesForSession([file1, file2], session);
|
||||
|
||||
const affectedFileResponse = session.executeCommandSeq<ts.projectSystem.protocol.CompileOnSaveAffectedFileListRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList,
|
||||
const affectedFileResponse = session.executeCommandSeq<ts.server.protocol.CompileOnSaveAffectedFileListRequest>({
|
||||
command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList,
|
||||
arguments: { file: file1.path }
|
||||
}).response as ts.projectSystem.protocol.CompileOnSaveAffectedFileListSingleProject[];
|
||||
}).response as ts.server.protocol.CompileOnSaveAffectedFileListSingleProject[];
|
||||
assert.deepEqual(affectedFileResponse, [
|
||||
{ fileNames: files.map(f => f.path), projectFileName: config.path, projectUsesOutFile: false }
|
||||
]);
|
||||
@@ -925,9 +926,9 @@ function bar() {
|
||||
// Change file2 get affected file list = will return only file2 if --declaration otherwise all files
|
||||
verifyLocalEdit(file2, "world", "hello", /*returnsAllFilesAsAffected*/ !declaration);
|
||||
|
||||
function verifyFileSave(file: ts.projectSystem.File) {
|
||||
const response = session.executeCommandSeq<ts.projectSystem.protocol.CompileOnSaveEmitFileRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile,
|
||||
function verifyFileSave(file: File) {
|
||||
const response = session.executeCommandSeq<ts.server.protocol.CompileOnSaveEmitFileRequest>({
|
||||
command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile,
|
||||
arguments: { file: file.path }
|
||||
}).response;
|
||||
assert.isTrue(response);
|
||||
@@ -948,24 +949,24 @@ function bar() {
|
||||
}
|
||||
}
|
||||
|
||||
function verifyLocalEdit(file: ts.projectSystem.File, oldText: string, newText: string, returnsAllFilesAsAffected?: boolean) {
|
||||
function verifyLocalEdit(file: File, oldText: string, newText: string, returnsAllFilesAsAffected?: boolean) {
|
||||
// Change file1 get affected file list
|
||||
session.executeCommandSeq<ts.projectSystem.protocol.UpdateOpenRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.UpdateOpen,
|
||||
session.executeCommandSeq<ts.server.protocol.UpdateOpenRequest>({
|
||||
command: ts.server.protocol.CommandTypes.UpdateOpen,
|
||||
arguments: {
|
||||
changedFiles: [{
|
||||
fileName: file.path,
|
||||
textChanges: [{
|
||||
newText,
|
||||
...ts.projectSystem.protocolTextSpanFromSubstring(file.content, oldText)
|
||||
...protocolTextSpanFromSubstring(file.content, oldText)
|
||||
}]
|
||||
}]
|
||||
}
|
||||
});
|
||||
const affectedFileResponse = session.executeCommandSeq<ts.projectSystem.protocol.CompileOnSaveAffectedFileListRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList,
|
||||
const affectedFileResponse = session.executeCommandSeq<ts.server.protocol.CompileOnSaveAffectedFileListRequest>({
|
||||
command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList,
|
||||
arguments: { file: file.path }
|
||||
}).response as ts.projectSystem.protocol.CompileOnSaveAffectedFileListSingleProject[];
|
||||
}).response as ts.server.protocol.CompileOnSaveAffectedFileListSingleProject[];
|
||||
assert.deepEqual(affectedFileResponse, [
|
||||
{ fileNames: [file.path, ...(returnsAllFilesAsAffected ? files.filter(f => f !== file).map(f => f.path) : ts.emptyArray)], projectFileName: config.path, projectUsesOutFile: false }
|
||||
]);
|
||||
@@ -977,9 +978,9 @@ function bar() {
|
||||
});
|
||||
|
||||
describe("unittests:: tsserver:: compileOnSave:: CompileOnSaveAffectedFileListRequest with and without projectFileName in request", () => {
|
||||
function insertString(session: ts.projectSystem.TestSession, file: ts.projectSystem.File) {
|
||||
session.executeCommandSeq<ts.projectSystem.protocol.ChangeRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.Change,
|
||||
function insertString(session: TestSession, file: File) {
|
||||
session.executeCommandSeq<ts.server.protocol.ChangeRequest>({
|
||||
command: ts.server.protocol.CommandTypes.Change,
|
||||
arguments: {
|
||||
file: file.path,
|
||||
line: 1,
|
||||
@@ -991,61 +992,61 @@ describe("unittests:: tsserver:: compileOnSave:: CompileOnSaveAffectedFileListRe
|
||||
});
|
||||
}
|
||||
|
||||
function logDirtyOfProjects(session: ts.projectSystem.TestSession) {
|
||||
session.logger.logs.push(`Project1 is dirty: ${session.getProjectService().configuredProjects.get(`${ts.tscWatch.projectRoot}/app1/tsconfig.json`)!.dirty}`);
|
||||
session.logger.logs.push(`Project2 is dirty: ${session.getProjectService().configuredProjects.get(`${ts.tscWatch.projectRoot}/app2/tsconfig.json`)!.dirty}`);
|
||||
function logDirtyOfProjects(session: TestSession) {
|
||||
session.logger.logs.push(`Project1 is dirty: ${session.getProjectService().configuredProjects.get(`/user/username/projects/myproject/app1/tsconfig.json`)!.dirty}`);
|
||||
session.logger.logs.push(`Project2 is dirty: ${session.getProjectService().configuredProjects.get(`/user/username/projects/myproject/app2/tsconfig.json`)!.dirty}`);
|
||||
}
|
||||
|
||||
function verify(subScenario: string, commandArgs: ts.projectSystem.protocol.FileRequestArgs) {
|
||||
function verify(subScenario: string, commandArgs: ts.server.protocol.FileRequestArgs) {
|
||||
it(subScenario, () => {
|
||||
const core: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/core/core.ts`,
|
||||
const core: File = {
|
||||
path: `/user/username/projects/myproject/core/core.ts`,
|
||||
content: "let z = 10;"
|
||||
};
|
||||
const app1: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/app1/app.ts`,
|
||||
const app1: File = {
|
||||
path: `/user/username/projects/myproject/app1/app.ts`,
|
||||
content: "let x = 10;"
|
||||
};
|
||||
const app2: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/app2/app.ts`,
|
||||
const app2: File = {
|
||||
path: `/user/username/projects/myproject/app2/app.ts`,
|
||||
content: "let y = 10;"
|
||||
};
|
||||
const app1Config: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/app1/tsconfig.json`,
|
||||
const app1Config: File = {
|
||||
path: `/user/username/projects/myproject/app1/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
files: ["app.ts", "../core/core.ts"],
|
||||
compilerOptions: { outFile: "build/output.js" },
|
||||
compileOnSave: true
|
||||
})
|
||||
};
|
||||
const app2Config: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/app2/tsconfig.json`,
|
||||
const app2Config: File = {
|
||||
path: `/user/username/projects/myproject/app2/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
files: ["app.ts", "../core/core.ts"],
|
||||
compilerOptions: { outFile: "build/output.js" },
|
||||
compileOnSave: true
|
||||
})
|
||||
};
|
||||
const files = [ts.projectSystem.libFile, core, app1, app2, app1Config, app2Config];
|
||||
const host = ts.projectSystem.createServerHost(files);
|
||||
const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) });
|
||||
ts.projectSystem.openFilesForSession([app1, app2, core], session);
|
||||
const files = [libFile, core, app1, app2, app1Config, app2Config];
|
||||
const host = createServerHost(files);
|
||||
const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) });
|
||||
openFilesForSession([app1, app2, core], session);
|
||||
insertString(session, app1);
|
||||
insertString(session, app2);
|
||||
logDirtyOfProjects(session);
|
||||
session.executeCommandSeq<ts.projectSystem.protocol.CompileOnSaveAffectedFileListRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList,
|
||||
session.executeCommandSeq<ts.server.protocol.CompileOnSaveAffectedFileListRequest>({
|
||||
command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList,
|
||||
arguments: commandArgs
|
||||
});
|
||||
logDirtyOfProjects(session);
|
||||
ts.projectSystem.baselineTsserverLogs("compileOnSave", subScenario, session);
|
||||
baselineTsserverLogs("compileOnSave", subScenario, session);
|
||||
});
|
||||
}
|
||||
verify("CompileOnSaveAffectedFileListRequest when projectFile is specified", {
|
||||
file: `${ts.tscWatch.projectRoot}/core/core.ts`,
|
||||
projectFileName: `${ts.tscWatch.projectRoot}/app1/tsconfig.json`
|
||||
file: `/user/username/projects/myproject/core/core.ts`,
|
||||
projectFileName: `/user/username/projects/myproject/app1/tsconfig.json`
|
||||
});
|
||||
verify("CompileOnSaveAffectedFileListRequest when projectFile is not specified", {
|
||||
file: `${ts.tscWatch.projectRoot}/core/core.ts`,
|
||||
file: `/user/username/projects/myproject/core/core.ts`,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,35 +1,37 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { createServerHost, File, libFile } from "../virtualFileSystemWithWatch";
|
||||
import { createSession, openFilesForSession, executeSessionRequest, TestTypingsInstaller, checkNumberOfProjects, checkProjectActualFiles } from "./helpers";
|
||||
|
||||
describe("unittests:: tsserver:: completions", () => {
|
||||
it("works", () => {
|
||||
const aTs: ts.projectSystem.File = {
|
||||
const aTs: File = {
|
||||
path: "/a.ts",
|
||||
content: "export const foo = 0;",
|
||||
};
|
||||
const bTs: ts.projectSystem.File = {
|
||||
const bTs: File = {
|
||||
path: "/b.ts",
|
||||
content: "foo",
|
||||
};
|
||||
const tsconfig: ts.projectSystem.File = {
|
||||
const tsconfig: File = {
|
||||
path: "/tsconfig.json",
|
||||
content: "{}",
|
||||
};
|
||||
|
||||
const session = ts.projectSystem.createSession(ts.projectSystem.createServerHost([aTs, bTs, tsconfig]));
|
||||
ts.projectSystem.openFilesForSession([aTs, bTs], session);
|
||||
const session = createSession(createServerHost([aTs, bTs, tsconfig]));
|
||||
openFilesForSession([aTs, bTs], session);
|
||||
|
||||
const requestLocation: ts.projectSystem.protocol.FileLocationRequestArgs = {
|
||||
const requestLocation: ts.server.protocol.FileLocationRequestArgs = {
|
||||
file: bTs.path,
|
||||
line: 1,
|
||||
offset: 3,
|
||||
};
|
||||
|
||||
const response = ts.projectSystem.executeSessionRequest<ts.projectSystem.protocol.CompletionsRequest, ts.projectSystem.protocol.CompletionInfoResponse>(session, ts.projectSystem.protocol.CommandTypes.CompletionInfo, {
|
||||
const response = executeSessionRequest<ts.server.protocol.CompletionsRequest, ts.server.protocol.CompletionInfoResponse>(session, ts.server.protocol.CommandTypes.CompletionInfo, {
|
||||
...requestLocation,
|
||||
includeExternalModuleExports: true,
|
||||
prefix: "foo",
|
||||
});
|
||||
const entry: ts.projectSystem.protocol.CompletionEntry = {
|
||||
const entry: ts.server.protocol.CompletionEntry = {
|
||||
hasAction: true,
|
||||
insertText: undefined,
|
||||
isRecommended: undefined,
|
||||
@@ -52,7 +54,7 @@ describe("unittests:: tsserver:: completions", () => {
|
||||
const exportMapKey = (response?.entries[0].data as any)?.exportMapKey;
|
||||
assert.isString(exportMapKey);
|
||||
delete (response?.entries[0].data as any).exportMapKey;
|
||||
assert.deepEqual<ts.projectSystem.protocol.CompletionInfo | undefined>(response, {
|
||||
assert.deepEqual<ts.server.protocol.CompletionInfo | undefined>(response, {
|
||||
flags: ts.CompletionInfoFlags.MayIncludeAutoImports,
|
||||
isGlobalCompletion: true,
|
||||
isIncomplete: undefined,
|
||||
@@ -62,13 +64,13 @@ describe("unittests:: tsserver:: completions", () => {
|
||||
entries: [entry],
|
||||
});
|
||||
|
||||
const detailsRequestArgs: ts.projectSystem.protocol.CompletionDetailsRequestArgs = {
|
||||
const detailsRequestArgs: ts.server.protocol.CompletionDetailsRequestArgs = {
|
||||
...requestLocation,
|
||||
entryNames: [{ name: "foo", source: "/a", data: { exportName: "foo", fileName: "/a.ts", exportMapKey } }],
|
||||
};
|
||||
|
||||
const detailsResponse = ts.projectSystem.executeSessionRequest<ts.projectSystem.protocol.CompletionDetailsRequest, ts.projectSystem.protocol.CompletionDetailsResponse>(session, ts.projectSystem.protocol.CommandTypes.CompletionDetails, detailsRequestArgs);
|
||||
const detailsCommon: ts.projectSystem.protocol.CompletionEntryDetails & ts.CompletionEntryDetails = {
|
||||
const detailsResponse = executeSessionRequest<ts.server.protocol.CompletionDetailsRequest, ts.server.protocol.CompletionDetailsResponse>(session, ts.server.protocol.CommandTypes.CompletionDetails, detailsRequestArgs);
|
||||
const detailsCommon: ts.server.protocol.CompletionEntryDetails & ts.CompletionEntryDetails = {
|
||||
displayParts: [
|
||||
ts.keywordPart(ts.SyntaxKind.ConstKeyword),
|
||||
ts.spacePart(),
|
||||
@@ -84,7 +86,7 @@ describe("unittests:: tsserver:: completions", () => {
|
||||
source: [{ text: "./a", kind: "text" }],
|
||||
sourceDisplay: [{ text: "./a", kind: "text" }],
|
||||
};
|
||||
assert.deepEqual<readonly ts.projectSystem.protocol.CompletionEntryDetails[] | undefined>(detailsResponse, [
|
||||
assert.deepEqual<readonly ts.server.protocol.CompletionEntryDetails[] | undefined>(detailsResponse, [
|
||||
{
|
||||
codeActions: [
|
||||
{
|
||||
@@ -109,14 +111,14 @@ describe("unittests:: tsserver:: completions", () => {
|
||||
},
|
||||
]);
|
||||
|
||||
interface CompletionDetailsFullRequest extends ts.projectSystem.protocol.FileLocationRequest {
|
||||
readonly command: ts.projectSystem.protocol.CommandTypes.CompletionDetailsFull;
|
||||
readonly arguments: ts.projectSystem.protocol.CompletionDetailsRequestArgs;
|
||||
interface CompletionDetailsFullRequest extends ts.server.protocol.FileLocationRequest {
|
||||
readonly command: ts.server.protocol.CommandTypes.CompletionDetailsFull;
|
||||
readonly arguments: ts.server.protocol.CompletionDetailsRequestArgs;
|
||||
}
|
||||
interface CompletionDetailsFullResponse extends ts.projectSystem.protocol.Response {
|
||||
interface CompletionDetailsFullResponse extends ts.server.protocol.Response {
|
||||
readonly body?: readonly ts.CompletionEntryDetails[];
|
||||
}
|
||||
const detailsFullResponse = ts.projectSystem.executeSessionRequest<CompletionDetailsFullRequest, CompletionDetailsFullResponse>(session, ts.projectSystem.protocol.CommandTypes.CompletionDetailsFull, detailsRequestArgs);
|
||||
const detailsFullResponse = executeSessionRequest<CompletionDetailsFullRequest, CompletionDetailsFullResponse>(session, ts.server.protocol.CommandTypes.CompletionDetailsFull, detailsRequestArgs);
|
||||
assert.deepEqual<readonly ts.CompletionEntryDetails[] | undefined>(detailsFullResponse, [
|
||||
{
|
||||
codeActions: [
|
||||
@@ -139,7 +141,7 @@ describe("unittests:: tsserver:: completions", () => {
|
||||
|
||||
it("works when files are included from two different drives of windows", () => {
|
||||
const projectRoot = "e:/myproject";
|
||||
const appPackage: ts.projectSystem.File = {
|
||||
const appPackage: File = {
|
||||
path: `${projectRoot}/package.json`,
|
||||
content: JSON.stringify({
|
||||
name: "test",
|
||||
@@ -150,7 +152,7 @@ describe("unittests:: tsserver:: completions", () => {
|
||||
}
|
||||
})
|
||||
};
|
||||
const appFile: ts.projectSystem.File = {
|
||||
const appFile: File = {
|
||||
path: `${projectRoot}/src/app.js`,
|
||||
content: `import React from 'react';
|
||||
import {
|
||||
@@ -160,37 +162,37 @@ import {
|
||||
};
|
||||
const localNodeModules = `${projectRoot}/node_modules`;
|
||||
const localAtTypes = `${localNodeModules}/@types`;
|
||||
const localReactPackage: ts.projectSystem.File = {
|
||||
const localReactPackage: File = {
|
||||
path: `${localAtTypes}/react/package.json`,
|
||||
content: JSON.stringify({
|
||||
name: "@types/react",
|
||||
version: "16.9.14",
|
||||
})
|
||||
};
|
||||
const localReact: ts.projectSystem.File = {
|
||||
const localReact: File = {
|
||||
path: `${localAtTypes}/react/index.d.ts`,
|
||||
content: `import * as PropTypes from 'prop-types';
|
||||
`
|
||||
};
|
||||
const localReactRouterDomPackage: ts.projectSystem.File = {
|
||||
const localReactRouterDomPackage: File = {
|
||||
path: `${localNodeModules}/react-router-dom/package.json`,
|
||||
content: JSON.stringify({
|
||||
name: "react-router-dom",
|
||||
version: "5.1.2",
|
||||
})
|
||||
};
|
||||
const localReactRouterDom: ts.projectSystem.File = {
|
||||
const localReactRouterDom: File = {
|
||||
path: `${localNodeModules}/react-router-dom/index.js`,
|
||||
content: `export function foo() {}`
|
||||
};
|
||||
const localPropTypesPackage: ts.projectSystem.File = {
|
||||
const localPropTypesPackage: File = {
|
||||
path: `${localAtTypes}/prop-types/package.json`,
|
||||
content: JSON.stringify({
|
||||
name: "@types/prop-types",
|
||||
version: "15.7.3",
|
||||
})
|
||||
};
|
||||
const localPropTypes: ts.projectSystem.File = {
|
||||
const localPropTypes: File = {
|
||||
path: `${localAtTypes}/prop-types/index.d.ts`,
|
||||
content: `export type ReactComponentLike =
|
||||
| string
|
||||
@@ -201,14 +203,14 @@ import {
|
||||
|
||||
const globalCacheLocation = `c:/typescript`;
|
||||
const globalAtTypes = `${globalCacheLocation}/node_modules/@types`;
|
||||
const globalReactRouterDomPackage: ts.projectSystem.File = {
|
||||
const globalReactRouterDomPackage: File = {
|
||||
path: `${globalAtTypes}/react-router-dom/package.json`,
|
||||
content: JSON.stringify({
|
||||
name: "@types/react-router-dom",
|
||||
version: "5.1.2",
|
||||
})
|
||||
};
|
||||
const globalReactRouterDom: ts.projectSystem.File = {
|
||||
const globalReactRouterDom: File = {
|
||||
path: `${globalAtTypes}/react-router-dom/index.d.ts`,
|
||||
content: `import * as React from 'react';
|
||||
export interface BrowserRouterProps {
|
||||
@@ -218,11 +220,11 @@ export interface BrowserRouterProps {
|
||||
keyLength?: number;
|
||||
}`
|
||||
};
|
||||
const globalReactPackage: ts.projectSystem.File = {
|
||||
const globalReactPackage: File = {
|
||||
path: `${globalAtTypes}/react/package.json`,
|
||||
content: localReactPackage.content
|
||||
};
|
||||
const globalReact: ts.projectSystem.File = {
|
||||
const globalReact: File = {
|
||||
path: `${globalAtTypes}/react/index.d.ts`,
|
||||
content: localReact.content
|
||||
};
|
||||
@@ -236,7 +238,7 @@ export interface BrowserRouterProps {
|
||||
];
|
||||
const files = [
|
||||
...filesInProject,
|
||||
appPackage, ts.projectSystem.libFile,
|
||||
appPackage, libFile,
|
||||
localReactPackage,
|
||||
localReactRouterDomPackage, localReactRouterDom,
|
||||
localPropTypesPackage,
|
||||
@@ -244,17 +246,17 @@ export interface BrowserRouterProps {
|
||||
globalReactPackage,
|
||||
];
|
||||
|
||||
const host = ts.projectSystem.createServerHost(files, { windowsStyleRoot: "c:/" });
|
||||
const session = ts.projectSystem.createSession(host, {
|
||||
typingsInstaller: new ts.projectSystem.TestTypingsInstaller(globalCacheLocation, /*throttleLimit*/ 5, host),
|
||||
const host = createServerHost(files, { windowsStyleRoot: "c:/" });
|
||||
const session = createSession(host, {
|
||||
typingsInstaller: new TestTypingsInstaller(globalCacheLocation, /*throttleLimit*/ 5, host),
|
||||
});
|
||||
const service = session.getProjectService();
|
||||
ts.projectSystem.openFilesForSession([appFile], session);
|
||||
ts.projectSystem.checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
const windowsStyleLibFilePath = "c:/" + ts.projectSystem.libFile.path.substring(1);
|
||||
ts.projectSystem.checkProjectActualFiles(service.inferredProjects[0], filesInProject.map(f => f.path).concat(windowsStyleLibFilePath));
|
||||
session.executeCommandSeq<ts.projectSystem.protocol.CompletionsRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.CompletionInfo,
|
||||
openFilesForSession([appFile], session);
|
||||
checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
const windowsStyleLibFilePath = "c:/" + libFile.path.substring(1);
|
||||
checkProjectActualFiles(service.inferredProjects[0], filesInProject.map(f => f.path).concat(windowsStyleLibFilePath));
|
||||
session.executeCommandSeq<ts.server.protocol.CompletionsRequest>({
|
||||
command: ts.server.protocol.CommandTypes.CompletionInfo,
|
||||
arguments: {
|
||||
file: appFile.path,
|
||||
line: 5,
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { createServerHost, File } from "../virtualFileSystemWithWatch";
|
||||
import { openFilesForSession, createSession } from "./helpers";
|
||||
|
||||
function createExportingModuleFile(path: string, exportPrefix: string, exportCount: number): ts.projectSystem.File {
|
||||
function createExportingModuleFile(path: string, exportPrefix: string, exportCount: number): File {
|
||||
return {
|
||||
path,
|
||||
content: ts.fill(exportCount, i => `export const ${exportPrefix}_${i} = ${i};`).join("\n"),
|
||||
};
|
||||
}
|
||||
|
||||
function createExportingModuleFiles(pathPrefix: string, fileCount: number, exportCount: number, getExportPrefix: (fileIndex: number) => string): ts.projectSystem.File[] {
|
||||
function createExportingModuleFiles(pathPrefix: string, fileCount: number, exportCount: number, getExportPrefix: (fileIndex: number) => string): File[] {
|
||||
return ts.fill(fileCount, fileIndex => createExportingModuleFile(
|
||||
`${pathPrefix}_${fileIndex}.ts`,
|
||||
getExportPrefix(fileIndex),
|
||||
exportCount));
|
||||
}
|
||||
|
||||
function createNodeModulesPackage(packageName: string, fileCount: number, exportCount: number, getExportPrefix: (fileIndex: number) => string): ts.projectSystem.File[] {
|
||||
function createNodeModulesPackage(packageName: string, fileCount: number, exportCount: number, getExportPrefix: (fileIndex: number) => string): File[] {
|
||||
const exportingFiles = createExportingModuleFiles(`/node_modules/${packageName}/file`, fileCount, exportCount, getExportPrefix);
|
||||
return [
|
||||
{
|
||||
@@ -31,17 +33,17 @@ function createNodeModulesPackage(packageName: string, fileCount: number, export
|
||||
];
|
||||
}
|
||||
|
||||
const indexFile: ts.projectSystem.File = {
|
||||
const indexFile: File = {
|
||||
path: "/index.ts",
|
||||
content: ""
|
||||
};
|
||||
|
||||
const tsconfigFile: ts.projectSystem.File = {
|
||||
const tsconfigFile: File = {
|
||||
path: "/tsconfig.json",
|
||||
content: `{ "compilerOptions": { "module": "commonjs" } }`
|
||||
};
|
||||
|
||||
const packageJsonFile: ts.projectSystem.File = {
|
||||
const packageJsonFile: File = {
|
||||
path: "/package.json",
|
||||
content: `{ "dependencies": { "dep-a": "*" } }`,
|
||||
};
|
||||
@@ -51,27 +53,27 @@ describe("unittests:: tsserver:: completionsIncomplete", () => {
|
||||
const excessFileCount = ts.Completions.moduleSpecifierResolutionLimit + 50;
|
||||
const exportingFiles = createExportingModuleFiles(`/lib/a`, ts.Completions.moduleSpecifierResolutionLimit + excessFileCount, 1, i => `aa_${i}_`);
|
||||
const { typeToTriggerCompletions, session } = setup([tsconfigFile, indexFile, ...exportingFiles]);
|
||||
ts.projectSystem.openFilesForSession([indexFile], session);
|
||||
openFilesForSession([indexFile], session);
|
||||
|
||||
typeToTriggerCompletions(indexFile.path, "a", completions => {
|
||||
assert(completions.isIncomplete);
|
||||
assert.lengthOf(completions.entries.filter(entry => (entry.data as any)?.moduleSpecifier), ts.Completions.moduleSpecifierResolutionLimit);
|
||||
assert.lengthOf(completions.entries.filter(entry => entry.source && !(entry.data as any)?.moduleSpecifier), excessFileCount);
|
||||
})
|
||||
.continueTyping("a", completions => {
|
||||
assert(completions.isIncomplete);
|
||||
assert.lengthOf(completions.entries.filter(entry => (entry.data as any)?.moduleSpecifier), ts.Completions.moduleSpecifierResolutionLimit * 2);
|
||||
})
|
||||
.continueTyping("_", completions => {
|
||||
assert(!completions.isIncomplete);
|
||||
assert.lengthOf(completions.entries.filter(entry => (entry.data as any)?.moduleSpecifier), exportingFiles.length);
|
||||
});
|
||||
.continueTyping("a", completions => {
|
||||
assert(completions.isIncomplete);
|
||||
assert.lengthOf(completions.entries.filter(entry => (entry.data as any)?.moduleSpecifier), ts.Completions.moduleSpecifierResolutionLimit * 2);
|
||||
})
|
||||
.continueTyping("_", completions => {
|
||||
assert(!completions.isIncomplete);
|
||||
assert.lengthOf(completions.entries.filter(entry => (entry.data as any)?.moduleSpecifier), exportingFiles.length);
|
||||
});
|
||||
});
|
||||
|
||||
it("resolves more when available from module specifier cache (1)", () => {
|
||||
const exportingFiles = createExportingModuleFiles(`/lib/a`, 50, 50, i => `aa_${i}_`);
|
||||
const { typeToTriggerCompletions, session } = setup([tsconfigFile, indexFile, ...exportingFiles]);
|
||||
ts.projectSystem.openFilesForSession([indexFile], session);
|
||||
openFilesForSession([indexFile], session);
|
||||
|
||||
typeToTriggerCompletions(indexFile.path, "a", completions => {
|
||||
assert(!completions.isIncomplete);
|
||||
@@ -82,7 +84,7 @@ describe("unittests:: tsserver:: completionsIncomplete", () => {
|
||||
const excessFileCount = 50;
|
||||
const exportingFiles = createExportingModuleFiles(`/lib/a`, ts.Completions.moduleSpecifierResolutionLimit + excessFileCount, 1, i => `aa_${i}_`);
|
||||
const { typeToTriggerCompletions, session } = setup([tsconfigFile, indexFile, ...exportingFiles]);
|
||||
ts.projectSystem.openFilesForSession([indexFile], session);
|
||||
openFilesForSession([indexFile], session);
|
||||
|
||||
typeToTriggerCompletions(indexFile.path, "a", completions => assert(completions.isIncomplete))
|
||||
.backspace()
|
||||
@@ -90,14 +92,14 @@ describe("unittests:: tsserver:: completionsIncomplete", () => {
|
||||
});
|
||||
|
||||
it("ambient module specifier resolutions do not count against the resolution limit", () => {
|
||||
const ambientFiles = ts.fill(100, (i): ts.projectSystem.File => ({
|
||||
const ambientFiles = ts.fill(100, (i): File => ({
|
||||
path: `/lib/ambient_${i}.ts`,
|
||||
content: `declare module "ambient_${i}" { export const aa_${i} = ${i}; }`,
|
||||
}));
|
||||
|
||||
const exportingFiles = createExportingModuleFiles(`/lib/a`, ts.Completions.moduleSpecifierResolutionLimit, 5, i => `aa_${i}_`);
|
||||
const { typeToTriggerCompletions, session } = setup([tsconfigFile, indexFile, ...ambientFiles, ...exportingFiles]);
|
||||
ts.projectSystem.openFilesForSession([indexFile], session);
|
||||
openFilesForSession([indexFile], session);
|
||||
|
||||
typeToTriggerCompletions(indexFile.path, "a", completions => {
|
||||
assert(!completions.isIncomplete);
|
||||
@@ -109,7 +111,7 @@ describe("unittests:: tsserver:: completionsIncomplete", () => {
|
||||
const exportingFiles = createExportingModuleFiles(`/lib/a`, ts.Completions.moduleSpecifierResolutionLimit, 1, i => `aa_${i}_`);
|
||||
const nodeModulesPackage = createNodeModulesPackage("dep-a", 50, 1, i => `depA_${i}_`);
|
||||
const { typeToTriggerCompletions, assertCompletionDetailsOk, session } = setup([tsconfigFile, packageJsonFile, indexFile, ...exportingFiles, ...nodeModulesPackage]);
|
||||
ts.projectSystem.openFilesForSession([indexFile], session);
|
||||
openFilesForSession([indexFile], session);
|
||||
|
||||
typeToTriggerCompletions(indexFile.path, "a", completions => assert(completions.isIncomplete))
|
||||
.continueTyping("_", completions => {
|
||||
@@ -122,7 +124,7 @@ describe("unittests:: tsserver:: completionsIncomplete", () => {
|
||||
});
|
||||
|
||||
it("works for transient symbols between requests", () => {
|
||||
const constantsDts: ts.projectSystem.File = {
|
||||
const constantsDts: File = {
|
||||
path: "/lib/foo/constants.d.ts",
|
||||
content: `
|
||||
type Signals = "SIGINT" | "SIGABRT";
|
||||
@@ -131,26 +133,26 @@ describe("unittests:: tsserver:: completionsIncomplete", () => {
|
||||
};
|
||||
const exportingFiles = createExportingModuleFiles("/lib/a", ts.Completions.moduleSpecifierResolutionLimit, 1, i => `S${i}`);
|
||||
const { typeToTriggerCompletions, session } = setup([tsconfigFile, indexFile, ...exportingFiles, constantsDts]);
|
||||
ts.projectSystem.openFilesForSession([indexFile], session);
|
||||
openFilesForSession([indexFile], session);
|
||||
|
||||
typeToTriggerCompletions(indexFile.path, "s", completions => {
|
||||
const sigint = completions.entries.find(e => e.name === "SIGINT");
|
||||
assert(sigint);
|
||||
assert(!(sigint.data as any).moduleSpecifier);
|
||||
})
|
||||
.continueTyping("i", completions => {
|
||||
const sigint = completions.entries.find(e => e.name === "SIGINT");
|
||||
assert((sigint!.data as any).moduleSpecifier);
|
||||
});
|
||||
.continueTyping("i", completions => {
|
||||
const sigint = completions.entries.find(e => e.name === "SIGINT");
|
||||
assert((sigint!.data as any).moduleSpecifier);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function setup(files: ts.projectSystem.File[]) {
|
||||
const host = ts.projectSystem.createServerHost(files);
|
||||
const session = ts.projectSystem.createSession(host);
|
||||
function setup(files: File[]) {
|
||||
const host = createServerHost(files);
|
||||
const session = createSession(host);
|
||||
const projectService = session.getProjectService();
|
||||
session.executeCommandSeq<ts.projectSystem.protocol.ConfigureRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.Configure,
|
||||
session.executeCommandSeq<ts.server.protocol.ConfigureRequest>({
|
||||
command: ts.server.protocol.CommandTypes.Configure,
|
||||
arguments: {
|
||||
preferences: {
|
||||
allowIncompleteCompletions: true,
|
||||
@@ -164,16 +166,16 @@ function setup(files: ts.projectSystem.File[]) {
|
||||
|
||||
return { host, session, projectService, typeToTriggerCompletions, assertCompletionDetailsOk };
|
||||
|
||||
function typeToTriggerCompletions(fileName: string, typedCharacters: string, cb?: (completions: ts.projectSystem.protocol.CompletionInfo) => void) {
|
||||
function typeToTriggerCompletions(fileName: string, typedCharacters: string, cb?: (completions: ts.server.protocol.CompletionInfo) => void) {
|
||||
const project = projectService.getDefaultProjectForFile(ts.server.toNormalizedPath(fileName), /*ensureProject*/ true)!;
|
||||
return type(typedCharacters, cb, /*isIncompleteContinuation*/ false);
|
||||
|
||||
function type(typedCharacters: string, cb: ((completions: ts.projectSystem.protocol.CompletionInfo) => void) | undefined, isIncompleteContinuation: boolean) {
|
||||
function type(typedCharacters: string, cb: ((completions: ts.server.protocol.CompletionInfo) => void) | undefined, isIncompleteContinuation: boolean) {
|
||||
const file = ts.Debug.checkDefined(project.getLanguageService(/*ensureSynchronized*/ true).getProgram()?.getSourceFile(fileName));
|
||||
const { line, character } = ts.getLineAndCharacterOfPosition(file, file.text.length);
|
||||
const oneBasedEditPosition = { line: line + 1, offset: character + 1 };
|
||||
session.executeCommandSeq<ts.projectSystem.protocol.UpdateOpenRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.UpdateOpen,
|
||||
session.executeCommandSeq<ts.server.protocol.UpdateOpenRequest>({
|
||||
command: ts.server.protocol.CommandTypes.UpdateOpen,
|
||||
arguments: {
|
||||
changedFiles: [{
|
||||
fileName,
|
||||
@@ -186,22 +188,22 @@ function setup(files: ts.projectSystem.File[]) {
|
||||
},
|
||||
});
|
||||
|
||||
const response = session.executeCommandSeq<ts.projectSystem.protocol.CompletionsRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.CompletionInfo,
|
||||
const response = session.executeCommandSeq<ts.server.protocol.CompletionsRequest>({
|
||||
command: ts.server.protocol.CommandTypes.CompletionInfo,
|
||||
arguments: {
|
||||
file: fileName,
|
||||
line: oneBasedEditPosition.line,
|
||||
offset: oneBasedEditPosition.offset,
|
||||
triggerKind: isIncompleteContinuation
|
||||
? ts.projectSystem.protocol.CompletionTriggerKind.TriggerForIncompleteCompletions
|
||||
? ts.server.protocol.CompletionTriggerKind.TriggerForIncompleteCompletions
|
||||
: undefined,
|
||||
}
|
||||
}).response as ts.projectSystem.protocol.CompletionInfo;
|
||||
}).response as ts.server.protocol.CompletionInfo;
|
||||
|
||||
cb?.(ts.Debug.checkDefined(response));
|
||||
return {
|
||||
backspace,
|
||||
continueTyping: (typedCharacters: string, cb: (completions: ts.projectSystem.protocol.CompletionInfo) => void) => {
|
||||
continueTyping: (typedCharacters: string, cb: (completions: ts.server.protocol.CompletionInfo) => void) => {
|
||||
return type(typedCharacters, cb, !!response.isIncomplete);
|
||||
},
|
||||
};
|
||||
@@ -213,8 +215,8 @@ function setup(files: ts.projectSystem.File[]) {
|
||||
const endLineCharacter = ts.getLineAndCharacterOfPosition(file, file.text.length);
|
||||
const oneBasedStartPosition = { line: startLineCharacter.line + 1, offset: startLineCharacter.character + 1 };
|
||||
const oneBasedEndPosition = { line: endLineCharacter.line + 1, offset: endLineCharacter.character + 1 };
|
||||
session.executeCommandSeq<ts.projectSystem.protocol.UpdateOpenRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.UpdateOpen,
|
||||
session.executeCommandSeq<ts.server.protocol.UpdateOpenRequest>({
|
||||
command: ts.server.protocol.CommandTypes.UpdateOpen,
|
||||
arguments: {
|
||||
changedFiles: [{
|
||||
fileName,
|
||||
@@ -229,19 +231,19 @@ function setup(files: ts.projectSystem.File[]) {
|
||||
|
||||
return {
|
||||
backspace,
|
||||
type: (typedCharacters: string, cb: (completions: ts.projectSystem.protocol.CompletionInfo) => void) => {
|
||||
type: (typedCharacters: string, cb: (completions: ts.server.protocol.CompletionInfo) => void) => {
|
||||
return type(typedCharacters, cb, /*isIncompleteContinuation*/ false);
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function assertCompletionDetailsOk(fileName: string, entry: ts.projectSystem.protocol.CompletionEntry) {
|
||||
function assertCompletionDetailsOk(fileName: string, entry: ts.server.protocol.CompletionEntry) {
|
||||
const project = projectService.getDefaultProjectForFile(ts.server.toNormalizedPath(fileName), /*ensureProject*/ true)!;
|
||||
const file = ts.Debug.checkDefined(project.getLanguageService(/*ensureSynchronized*/ true).getProgram()?.getSourceFile(fileName));
|
||||
const { line, character } = ts.getLineAndCharacterOfPosition(file, file.text.length - 1);
|
||||
const details = session.executeCommandSeq<ts.projectSystem.protocol.CompletionDetailsRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.CompletionDetails,
|
||||
const details = session.executeCommandSeq<ts.server.protocol.CompletionDetailsRequest>({
|
||||
command: ts.server.protocol.CommandTypes.CompletionDetails,
|
||||
arguments: {
|
||||
file: fileName,
|
||||
line: line + 1,
|
||||
@@ -252,7 +254,7 @@ function setup(files: ts.projectSystem.File[]) {
|
||||
data: entry.data,
|
||||
}]
|
||||
}
|
||||
}).response as ts.projectSystem.protocol.CompletionEntryDetails[];
|
||||
}).response as ts.server.protocol.CompletionEntryDetails[];
|
||||
|
||||
assert(details[0]);
|
||||
assert(details[0].codeActions);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { createServerHost, File, libFile } from "../virtualFileSystemWithWatch";
|
||||
import { createProjectService, checkNumberOfConfiguredProjects, checkNumberOfInferredProjects, createLoggerWithInMemoryLogs, checkNumberOfProjects, baselineTsserverLogs } from "./helpers";
|
||||
|
||||
describe("unittests:: tsserver:: searching for config file", () => {
|
||||
it("should stop at projectRootPath if given", () => {
|
||||
@@ -10,17 +11,17 @@ describe("unittests:: tsserver:: searching for config file", () => {
|
||||
path: "/tsconfig.json",
|
||||
content: "{}"
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([f1, configFile]);
|
||||
const service = ts.projectSystem.createProjectService(host);
|
||||
const host = createServerHost([f1, configFile]);
|
||||
const service = createProjectService(host);
|
||||
service.openClientFile(f1.path, /*fileContent*/ undefined, /*scriptKind*/ undefined, "/a");
|
||||
|
||||
ts.projectSystem.checkNumberOfConfiguredProjects(service, 0);
|
||||
ts.projectSystem.checkNumberOfInferredProjects(service, 1);
|
||||
checkNumberOfConfiguredProjects(service, 0);
|
||||
checkNumberOfInferredProjects(service, 1);
|
||||
|
||||
service.closeClientFile(f1.path);
|
||||
service.openClientFile(f1.path);
|
||||
ts.projectSystem.checkNumberOfConfiguredProjects(service, 1);
|
||||
ts.projectSystem.checkNumberOfInferredProjects(service, 0);
|
||||
checkNumberOfConfiguredProjects(service, 1);
|
||||
checkNumberOfInferredProjects(service, 0);
|
||||
});
|
||||
|
||||
it("should use projectRootPath when searching for inferred project again", () => {
|
||||
@@ -38,15 +39,15 @@ describe("unittests:: tsserver:: searching for config file", () => {
|
||||
path: "/a/b/projects/tsconfig.json",
|
||||
content: "{}"
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([f1, ts.projectSystem.libFile, configFile, configFile2]);
|
||||
const service = ts.projectSystem.createProjectService(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) });
|
||||
const host = createServerHost([f1, libFile, configFile, configFile2]);
|
||||
const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) });
|
||||
service.openClientFile(f1.path, /*fileContent*/ undefined, /*scriptKind*/ undefined, projectDir);
|
||||
|
||||
// Delete config file - should create inferred project and not configured project
|
||||
host.deleteFile(configFile.path);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
ts.projectSystem.checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
ts.projectSystem.baselineTsserverLogs("configFileSearch", "should use projectRootPath when searching for inferred project again", service);
|
||||
checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
baselineTsserverLogs("configFileSearch", "should use projectRootPath when searching for inferred project again", service);
|
||||
});
|
||||
|
||||
it("should use projectRootPath when searching for inferred project again 2", () => {
|
||||
@@ -64,39 +65,39 @@ describe("unittests:: tsserver:: searching for config file", () => {
|
||||
path: "/a/b/projects/tsconfig.json",
|
||||
content: "{}"
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([f1, ts.projectSystem.libFile, configFile, configFile2]);
|
||||
const service = ts.projectSystem.createProjectService(host, {
|
||||
const host = createServerHost([f1, libFile, configFile, configFile2]);
|
||||
const service = createProjectService(host, {
|
||||
useSingleInferredProject: true,
|
||||
useInferredProjectPerProjectRoot: true,
|
||||
logger: ts.projectSystem.createLoggerWithInMemoryLogs(host),
|
||||
logger: createLoggerWithInMemoryLogs(host),
|
||||
});
|
||||
service.openClientFile(f1.path, /*fileContent*/ undefined, /*scriptKind*/ undefined, projectDir);
|
||||
|
||||
// Delete config file - should create inferred project with project root path set
|
||||
host.deleteFile(configFile.path);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
ts.projectSystem.baselineTsserverLogs("configFileSearch", "should use projectRootPath when searching for inferred project again 2", service);
|
||||
baselineTsserverLogs("configFileSearch", "should use projectRootPath when searching for inferred project again 2", service);
|
||||
});
|
||||
|
||||
describe("when the opened file is not from project root", () => {
|
||||
const projectRoot = "/a/b/projects/project";
|
||||
const file: ts.projectSystem.File = {
|
||||
const file: File = {
|
||||
path: `${projectRoot}/src/index.ts`,
|
||||
content: "let y = 10"
|
||||
};
|
||||
const tsconfig: ts.projectSystem.File = {
|
||||
const tsconfig: File = {
|
||||
path: `${projectRoot}/tsconfig.json`,
|
||||
content: "{}"
|
||||
};
|
||||
function openClientFile(files: ts.projectSystem.File[]) {
|
||||
const host = ts.projectSystem.createServerHost(files);
|
||||
const projectService = ts.projectSystem.createProjectService(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) });
|
||||
function openClientFile(files: File[]) {
|
||||
const host = createServerHost(files);
|
||||
const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) });
|
||||
projectService.openClientFile(file.path, /*fileContent*/ undefined, /*scriptKind*/ undefined, "/a/b/projects/proj");
|
||||
return { host, projectService };
|
||||
}
|
||||
|
||||
it("tsconfig for the file exists", () => {
|
||||
const { host, projectService } = openClientFile([file, ts.projectSystem.libFile, tsconfig]);
|
||||
const { host, projectService } = openClientFile([file, libFile, tsconfig]);
|
||||
|
||||
host.deleteFile(tsconfig.path);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
@@ -104,11 +105,11 @@ describe("unittests:: tsserver:: searching for config file", () => {
|
||||
host.writeFile(tsconfig.path, tsconfig.content);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
|
||||
ts.projectSystem.baselineTsserverLogs("configFileSearch", "tsconfig for the file exists", projectService);
|
||||
baselineTsserverLogs("configFileSearch", "tsconfig for the file exists", projectService);
|
||||
});
|
||||
|
||||
it("tsconfig for the file does not exist", () => {
|
||||
const { host, projectService } = openClientFile([file, ts.projectSystem.libFile]);
|
||||
const { host, projectService } = openClientFile([file, libFile]);
|
||||
|
||||
host.writeFile(tsconfig.path, tsconfig.content);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
@@ -116,7 +117,7 @@ describe("unittests:: tsserver:: searching for config file", () => {
|
||||
host.deleteFile(tsconfig.path);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
|
||||
ts.projectSystem.baselineTsserverLogs("configFileSearch", "tsconfig for the file does not exist", projectService);
|
||||
baselineTsserverLogs("configFileSearch", "tsconfig for the file does not exist", projectService);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -124,10 +125,10 @@ describe("unittests:: tsserver:: searching for config file", () => {
|
||||
function verifyConfigFileWatch(scenario: string, projectRootPath: string | undefined) {
|
||||
it(scenario, () => {
|
||||
const path = `/root/teams/VSCode68/Shared Documents/General/jt-ts-test-workspace/x.js`;
|
||||
const host = ts.projectSystem.createServerHost([ts.projectSystem.libFile, { path, content: "const x = 10" }], { useCaseSensitiveFileNames: true });
|
||||
const service = ts.projectSystem.createProjectService(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) });
|
||||
const host = createServerHost([libFile, { path, content: "const x = 10" }], { useCaseSensitiveFileNames: true });
|
||||
const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) });
|
||||
service.openClientFile(path, /*fileContent*/ undefined, /*scriptKind*/ undefined, projectRootPath);
|
||||
ts.projectSystem.baselineTsserverLogs("configFileSearch", scenario, service);
|
||||
baselineTsserverLogs("configFileSearch", scenario, service);
|
||||
});
|
||||
}
|
||||
verifyConfigFileWatch("when projectRootPath is not present", /*projectRootPath*/ undefined);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,19 +1,21 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { createServerHost, File } from "../virtualFileSystemWithWatch";
|
||||
import { DocumentSpanFromSubstring, textSpanFromSubstring, TestSession, openFilesForSession, closeFilesForSession, createSession, checkNumberOfProjects, checkProjectActualFiles, executeSessionRequest, protocolFileLocationFromSubstring, protocolFileSpanWithContextFromSubstring, protocolTextSpanFromSubstring, protocolFileSpanFromSubstring, makeReferenceItem, protocolLocationFromSubstring, protocolRenameSpanFromSubstring } from "./helpers";
|
||||
|
||||
function documentSpanFromSubstring({ file, text, contextText, options, contextOptions }: ts.projectSystem.DocumentSpanFromSubstring): ts.DocumentSpan {
|
||||
function documentSpanFromSubstring({ file, text, contextText, options, contextOptions }: DocumentSpanFromSubstring): ts.DocumentSpan {
|
||||
const contextSpan = contextText !== undefined ? documentSpanFromSubstring({ file, text: contextText, options: contextOptions }) : undefined;
|
||||
return {
|
||||
fileName: file.path,
|
||||
textSpan: ts.projectSystem.textSpanFromSubstring(file.content, text, options),
|
||||
textSpan: textSpanFromSubstring(file.content, text, options),
|
||||
...contextSpan && { contextSpan: contextSpan.textSpan }
|
||||
};
|
||||
}
|
||||
|
||||
function renameLocation(input: ts.projectSystem.DocumentSpanFromSubstring): ts.RenameLocation {
|
||||
function renameLocation(input: DocumentSpanFromSubstring): ts.RenameLocation {
|
||||
return documentSpanFromSubstring(input);
|
||||
}
|
||||
|
||||
interface MakeReferenceEntry extends ts.projectSystem.DocumentSpanFromSubstring {
|
||||
interface MakeReferenceEntry extends DocumentSpanFromSubstring {
|
||||
isDefinition?: boolean;
|
||||
isWriteAccess?: boolean;
|
||||
}
|
||||
@@ -30,19 +32,19 @@ function makeReferencedSymbolEntry({ isDefinition, isWriteAccess, ...rest }: Mak
|
||||
return result;
|
||||
}
|
||||
|
||||
function checkDeclarationFiles(file: ts.projectSystem.File, session: ts.projectSystem.TestSession, expectedFiles: readonly ts.projectSystem.File[]): void {
|
||||
ts.projectSystem.openFilesForSession([file], session);
|
||||
function checkDeclarationFiles(file: File, session: TestSession, expectedFiles: readonly File[]): void {
|
||||
openFilesForSession([file], session);
|
||||
const project = ts.Debug.checkDefined(session.getProjectService().getDefaultProjectForFile(file.path as ts.server.NormalizedPath, /*ensureProject*/ false));
|
||||
const program = project.getCurrentProgram()!;
|
||||
const output = ts.getFileEmitOutput(program, ts.Debug.checkDefined(program.getSourceFile(file.path)), /*emitOnlyDtsFiles*/ true);
|
||||
ts.projectSystem.closeFilesForSession([file], session);
|
||||
closeFilesForSession([file], session);
|
||||
|
||||
ts.Debug.assert(!output.emitSkipped);
|
||||
assert.deepEqual(output.outputFiles, expectedFiles.map((e): ts.OutputFile => ({ name: e.path, text: e.content, writeByteOrderMark: false })));
|
||||
}
|
||||
|
||||
describe("unittests:: tsserver:: with declaration file maps:: project references", () => {
|
||||
const aTs: ts.projectSystem.File = {
|
||||
const aTs: File = {
|
||||
path: "/a/a.ts",
|
||||
content: "export function fnA() {}\nexport interface IfaceA {}\nexport const instanceA: IfaceA = {};",
|
||||
};
|
||||
@@ -53,7 +55,7 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
composite: true,
|
||||
};
|
||||
const configContent = JSON.stringify({ compilerOptions });
|
||||
const aTsconfig: ts.projectSystem.File = { path: "/a/tsconfig.json", content: configContent };
|
||||
const aTsconfig: File = { path: "/a/tsconfig.json", content: configContent };
|
||||
|
||||
const aDtsMapContent: ts.RawSourceMap = {
|
||||
version: 3,
|
||||
@@ -63,21 +65,21 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
names: [],
|
||||
mappings: "AAAA,wBAAgB,GAAG,SAAK;AACxB,MAAM,WAAW,MAAM;CAAG;AAC1B,eAAO,MAAM,SAAS,EAAE,MAAW,CAAC"
|
||||
};
|
||||
const aDtsMap: ts.projectSystem.File = {
|
||||
const aDtsMap: File = {
|
||||
path: "/a/bin/a.d.ts.map",
|
||||
content: JSON.stringify(aDtsMapContent),
|
||||
};
|
||||
const aDts: ts.projectSystem.File = {
|
||||
const aDts: File = {
|
||||
path: "/a/bin/a.d.ts",
|
||||
// ${""} is needed to mangle the sourceMappingURL part or it breaks the build
|
||||
content: `export declare function fnA(): void;\nexport interface IfaceA {\n}\nexport declare const instanceA: IfaceA;\n//# source${""}MappingURL=a.d.ts.map`,
|
||||
};
|
||||
|
||||
const bTs: ts.projectSystem.File = {
|
||||
const bTs: File = {
|
||||
path: "/b/b.ts",
|
||||
content: "export function fnB() {}",
|
||||
};
|
||||
const bTsconfig: ts.projectSystem.File = { path: "/b/tsconfig.json", content: configContent };
|
||||
const bTsconfig: File = { path: "/b/tsconfig.json", content: configContent };
|
||||
|
||||
const bDtsMapContent: ts.RawSourceMap = {
|
||||
version: 3,
|
||||
@@ -87,32 +89,32 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
names: [],
|
||||
mappings: "AAAA,wBAAgB,GAAG,SAAK",
|
||||
};
|
||||
const bDtsMap: ts.projectSystem.File = {
|
||||
const bDtsMap: File = {
|
||||
path: "/b/bin/b.d.ts.map",
|
||||
content: JSON.stringify(bDtsMapContent),
|
||||
};
|
||||
const bDts: ts.projectSystem.File = {
|
||||
const bDts: File = {
|
||||
// ${""} is need to mangle the sourceMappingURL part so it doesn't break the build
|
||||
path: "/b/bin/b.d.ts",
|
||||
content: `export declare function fnB(): void;\n//# source${""}MappingURL=b.d.ts.map`,
|
||||
};
|
||||
|
||||
const dummyFile: ts.projectSystem.File = {
|
||||
const dummyFile: File = {
|
||||
path: "/dummy/dummy.ts",
|
||||
content: "let a = 10;"
|
||||
};
|
||||
|
||||
const userTs: ts.projectSystem.File = {
|
||||
const userTs: File = {
|
||||
path: "/user/user.ts",
|
||||
content: 'import * as a from "../a/bin/a";\nimport * as b from "../b/bin/b";\nexport function fnUser() { a.fnA(); b.fnB(); a.instanceA; }',
|
||||
};
|
||||
|
||||
const userTsForConfigProject: ts.projectSystem.File = {
|
||||
const userTsForConfigProject: File = {
|
||||
path: "/user/user.ts",
|
||||
content: 'import * as a from "../a/a";\nimport * as b from "../b/b";\nexport function fnUser() { a.fnA(); b.fnB(); a.instanceA; }',
|
||||
};
|
||||
|
||||
const userTsconfig: ts.projectSystem.File = {
|
||||
const userTsconfig: File = {
|
||||
path: "/user/tsconfig.json",
|
||||
content: JSON.stringify({
|
||||
file: ["user.ts"],
|
||||
@@ -121,8 +123,8 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
};
|
||||
|
||||
function makeSampleProjects(addUserTsConfig?: boolean, keepAllFiles?: boolean) {
|
||||
const host = ts.projectSystem.createServerHost([aTs, aTsconfig, aDtsMap, aDts, bTsconfig, bTs, bDtsMap, bDts, ...(addUserTsConfig ? [userTsForConfigProject, userTsconfig] : [userTs]), dummyFile]);
|
||||
const session = ts.projectSystem.createSession(host);
|
||||
const host = createServerHost([aTs, aTsconfig, aDtsMap, aDts, bTsconfig, bTs, bDtsMap, bDts, ...(addUserTsConfig ? [userTsForConfigProject, userTsconfig] : [userTs]), dummyFile]);
|
||||
const session = createSession(host);
|
||||
|
||||
checkDeclarationFiles(aTs, session, [aDtsMap, aDts]);
|
||||
checkDeclarationFiles(bTs, session, [bDtsMap, bDts]);
|
||||
@@ -132,70 +134,70 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
host.deleteFile(bTs.path);
|
||||
}
|
||||
|
||||
ts.projectSystem.openFilesForSession([userTs], session);
|
||||
openFilesForSession([userTs], session);
|
||||
const service = session.getProjectService();
|
||||
// If config file then userConfig project and bConfig project since it is referenced
|
||||
ts.projectSystem.checkNumberOfProjects(service, addUserTsConfig ? { configuredProjects: 2 } : { inferredProjects: 1 });
|
||||
checkNumberOfProjects(service, addUserTsConfig ? { configuredProjects: 2 } : { inferredProjects: 1 });
|
||||
return session;
|
||||
}
|
||||
|
||||
function verifyInferredProjectUnchanged(session: ts.projectSystem.TestSession) {
|
||||
ts.projectSystem.checkProjectActualFiles(session.getProjectService().inferredProjects[0], [userTs.path, aDts.path, bDts.path]);
|
||||
function verifyInferredProjectUnchanged(session: TestSession) {
|
||||
checkProjectActualFiles(session.getProjectService().inferredProjects[0], [userTs.path, aDts.path, bDts.path]);
|
||||
}
|
||||
|
||||
function verifyDummyProject(session: ts.projectSystem.TestSession) {
|
||||
ts.projectSystem.checkProjectActualFiles(session.getProjectService().inferredProjects[0], [dummyFile.path]);
|
||||
function verifyDummyProject(session: TestSession) {
|
||||
checkProjectActualFiles(session.getProjectService().inferredProjects[0], [dummyFile.path]);
|
||||
}
|
||||
|
||||
function verifyOnlyOrphanInferredProject(session: ts.projectSystem.TestSession) {
|
||||
ts.projectSystem.openFilesForSession([dummyFile], session);
|
||||
ts.projectSystem.checkNumberOfProjects(session.getProjectService(), { inferredProjects: 1 });
|
||||
function verifyOnlyOrphanInferredProject(session: TestSession) {
|
||||
openFilesForSession([dummyFile], session);
|
||||
checkNumberOfProjects(session.getProjectService(), { inferredProjects: 1 });
|
||||
verifyDummyProject(session);
|
||||
}
|
||||
|
||||
function verifySingleInferredProject(session: ts.projectSystem.TestSession) {
|
||||
ts.projectSystem.checkNumberOfProjects(session.getProjectService(), { inferredProjects: 1 });
|
||||
function verifySingleInferredProject(session: TestSession) {
|
||||
checkNumberOfProjects(session.getProjectService(), { inferredProjects: 1 });
|
||||
verifyInferredProjectUnchanged(session);
|
||||
|
||||
// Close user file should close all the projects after opening dummy file
|
||||
ts.projectSystem.closeFilesForSession([userTs], session);
|
||||
closeFilesForSession([userTs], session);
|
||||
verifyOnlyOrphanInferredProject(session);
|
||||
}
|
||||
|
||||
function verifyATsConfigProject(session: ts.projectSystem.TestSession) {
|
||||
ts.projectSystem.checkProjectActualFiles(session.getProjectService().configuredProjects.get(aTsconfig.path)!, [aTs.path, aTsconfig.path]);
|
||||
function verifyATsConfigProject(session: TestSession) {
|
||||
checkProjectActualFiles(session.getProjectService().configuredProjects.get(aTsconfig.path)!, [aTs.path, aTsconfig.path]);
|
||||
}
|
||||
|
||||
function verifyATsConfigOriginalProject(session: ts.projectSystem.TestSession) {
|
||||
ts.projectSystem.checkNumberOfProjects(session.getProjectService(), { inferredProjects: 1, configuredProjects: 1 });
|
||||
function verifyATsConfigOriginalProject(session: TestSession) {
|
||||
checkNumberOfProjects(session.getProjectService(), { inferredProjects: 1, configuredProjects: 1 });
|
||||
verifyInferredProjectUnchanged(session);
|
||||
verifyATsConfigProject(session);
|
||||
// Close user file should close all the projects
|
||||
ts.projectSystem.closeFilesForSession([userTs], session);
|
||||
closeFilesForSession([userTs], session);
|
||||
verifyOnlyOrphanInferredProject(session);
|
||||
}
|
||||
|
||||
function verifyATsConfigWhenOpened(session: ts.projectSystem.TestSession) {
|
||||
ts.projectSystem.checkNumberOfProjects(session.getProjectService(), { inferredProjects: 1, configuredProjects: 1 });
|
||||
function verifyATsConfigWhenOpened(session: TestSession) {
|
||||
checkNumberOfProjects(session.getProjectService(), { inferredProjects: 1, configuredProjects: 1 });
|
||||
verifyInferredProjectUnchanged(session);
|
||||
verifyATsConfigProject(session);
|
||||
|
||||
ts.projectSystem.closeFilesForSession([userTs], session);
|
||||
ts.projectSystem.openFilesForSession([dummyFile], session);
|
||||
ts.projectSystem.checkNumberOfProjects(session.getProjectService(), { inferredProjects: 1, configuredProjects: 1 });
|
||||
closeFilesForSession([userTs], session);
|
||||
openFilesForSession([dummyFile], session);
|
||||
checkNumberOfProjects(session.getProjectService(), { inferredProjects: 1, configuredProjects: 1 });
|
||||
verifyDummyProject(session);
|
||||
verifyATsConfigProject(session); // ATsConfig should still be alive
|
||||
}
|
||||
|
||||
function verifyUserTsConfigProject(session: ts.projectSystem.TestSession) {
|
||||
ts.projectSystem.checkProjectActualFiles(session.getProjectService().configuredProjects.get(userTsconfig.path)!, [userTs.path, aTs.path, userTsconfig.path]);
|
||||
function verifyUserTsConfigProject(session: TestSession) {
|
||||
checkProjectActualFiles(session.getProjectService().configuredProjects.get(userTsconfig.path)!, [userTs.path, aTs.path, userTsconfig.path]);
|
||||
}
|
||||
|
||||
it("goToDefinition", () => {
|
||||
const session = makeSampleProjects();
|
||||
const response = ts.projectSystem.executeSessionRequest<ts.projectSystem.protocol.DefinitionRequest, ts.projectSystem.protocol.DefinitionResponse>(session, ts.projectSystem.protocol.CommandTypes.Definition, ts.projectSystem.protocolFileLocationFromSubstring(userTs, "fnA()"));
|
||||
const response = executeSessionRequest<ts.server.protocol.DefinitionRequest, ts.server.protocol.DefinitionResponse>(session, ts.server.protocol.CommandTypes.Definition, protocolFileLocationFromSubstring(userTs, "fnA()"));
|
||||
assert.deepEqual(response, [
|
||||
ts.projectSystem.protocolFileSpanWithContextFromSubstring({
|
||||
protocolFileSpanWithContextFromSubstring({
|
||||
file: aTs,
|
||||
text: "fnA",
|
||||
contextText: "export function fnA() {}"
|
||||
@@ -206,11 +208,11 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
|
||||
it("getDefinitionAndBoundSpan", () => {
|
||||
const session = makeSampleProjects();
|
||||
const response = ts.projectSystem.executeSessionRequest<ts.projectSystem.protocol.DefinitionAndBoundSpanRequest, ts.projectSystem.protocol.DefinitionAndBoundSpanResponse>(session, ts.projectSystem.protocol.CommandTypes.DefinitionAndBoundSpan, ts.projectSystem.protocolFileLocationFromSubstring(userTs, "fnA()"));
|
||||
const response = executeSessionRequest<ts.server.protocol.DefinitionAndBoundSpanRequest, ts.server.protocol.DefinitionAndBoundSpanResponse>(session, ts.server.protocol.CommandTypes.DefinitionAndBoundSpan, protocolFileLocationFromSubstring(userTs, "fnA()"));
|
||||
assert.deepEqual(response, {
|
||||
textSpan: ts.projectSystem.protocolTextSpanFromSubstring(userTs.content, "fnA"),
|
||||
textSpan: protocolTextSpanFromSubstring(userTs.content, "fnA"),
|
||||
definitions: [
|
||||
ts.projectSystem.protocolFileSpanWithContextFromSubstring({
|
||||
protocolFileSpanWithContextFromSubstring({
|
||||
file: aTs,
|
||||
text: "fnA",
|
||||
contextText: "export function fnA() {}"
|
||||
@@ -222,38 +224,38 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
|
||||
it("getDefinitionAndBoundSpan with file navigation", () => {
|
||||
const session = makeSampleProjects(/*addUserTsConfig*/ true);
|
||||
const response = ts.projectSystem.executeSessionRequest<ts.projectSystem.protocol.DefinitionAndBoundSpanRequest, ts.projectSystem.protocol.DefinitionAndBoundSpanResponse>(session, ts.projectSystem.protocol.CommandTypes.DefinitionAndBoundSpan, ts.projectSystem.protocolFileLocationFromSubstring(userTs, "fnA()"));
|
||||
const response = executeSessionRequest<ts.server.protocol.DefinitionAndBoundSpanRequest, ts.server.protocol.DefinitionAndBoundSpanResponse>(session, ts.server.protocol.CommandTypes.DefinitionAndBoundSpan, protocolFileLocationFromSubstring(userTs, "fnA()"));
|
||||
assert.deepEqual(response, {
|
||||
textSpan: ts.projectSystem.protocolTextSpanFromSubstring(userTs.content, "fnA"),
|
||||
textSpan: protocolTextSpanFromSubstring(userTs.content, "fnA"),
|
||||
definitions: [
|
||||
ts.projectSystem.protocolFileSpanWithContextFromSubstring({
|
||||
protocolFileSpanWithContextFromSubstring({
|
||||
file: aTs,
|
||||
text: "fnA",
|
||||
contextText: "export function fnA() {}"
|
||||
})
|
||||
],
|
||||
});
|
||||
ts.projectSystem.checkNumberOfProjects(session.getProjectService(), { configuredProjects: 2 });
|
||||
checkNumberOfProjects(session.getProjectService(), { configuredProjects: 2 });
|
||||
verifyUserTsConfigProject(session);
|
||||
|
||||
// Navigate to the definition
|
||||
ts.projectSystem.closeFilesForSession([userTs], session);
|
||||
ts.projectSystem.openFilesForSession([aTs], session);
|
||||
closeFilesForSession([userTs], session);
|
||||
openFilesForSession([aTs], session);
|
||||
|
||||
// UserTs configured project should be alive
|
||||
ts.projectSystem.checkNumberOfProjects(session.getProjectService(), { configuredProjects: 3 });
|
||||
checkNumberOfProjects(session.getProjectService(), { configuredProjects: 3 });
|
||||
verifyUserTsConfigProject(session);
|
||||
verifyATsConfigProject(session);
|
||||
|
||||
ts.projectSystem.closeFilesForSession([aTs], session);
|
||||
closeFilesForSession([aTs], session);
|
||||
verifyOnlyOrphanInferredProject(session);
|
||||
});
|
||||
|
||||
it("goToType", () => {
|
||||
const session = makeSampleProjects();
|
||||
const response = ts.projectSystem.executeSessionRequest<ts.projectSystem.protocol.TypeDefinitionRequest, ts.projectSystem.protocol.TypeDefinitionResponse>(session, ts.projectSystem.protocol.CommandTypes.TypeDefinition, ts.projectSystem.protocolFileLocationFromSubstring(userTs, "instanceA"));
|
||||
const response = executeSessionRequest<ts.server.protocol.TypeDefinitionRequest, ts.server.protocol.TypeDefinitionResponse>(session, ts.server.protocol.CommandTypes.TypeDefinition, protocolFileLocationFromSubstring(userTs, "instanceA"));
|
||||
assert.deepEqual(response, [
|
||||
ts.projectSystem.protocolFileSpanWithContextFromSubstring({
|
||||
protocolFileSpanWithContextFromSubstring({
|
||||
file: aTs,
|
||||
text: "IfaceA",
|
||||
contextText: "export interface IfaceA {}"
|
||||
@@ -264,9 +266,9 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
|
||||
it("goToImplementation", () => {
|
||||
const session = makeSampleProjects();
|
||||
const response = ts.projectSystem.executeSessionRequest<ts.projectSystem.protocol.ImplementationRequest, ts.projectSystem.protocol.ImplementationResponse>(session, ts.projectSystem.protocol.CommandTypes.Implementation, ts.projectSystem.protocolFileLocationFromSubstring(userTs, "fnA()"));
|
||||
const response = executeSessionRequest<ts.server.protocol.ImplementationRequest, ts.server.protocol.ImplementationResponse>(session, ts.server.protocol.CommandTypes.Implementation, protocolFileLocationFromSubstring(userTs, "fnA()"));
|
||||
assert.deepEqual(response, [
|
||||
ts.projectSystem.protocolFileSpanWithContextFromSubstring({
|
||||
protocolFileSpanWithContextFromSubstring({
|
||||
file: aTs,
|
||||
text: "fnA",
|
||||
contextText: "export function fnA() {}"
|
||||
@@ -276,10 +278,10 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
|
||||
it("goToDefinition -- target does not exist", () => {
|
||||
const session = makeSampleProjects();
|
||||
const response = ts.projectSystem.executeSessionRequest<ts.projectSystem.protocol.DefinitionRequest, ts.projectSystem.protocol.DefinitionResponse>(session, ts.projectSystem.CommandNames.Definition, ts.projectSystem.protocolFileLocationFromSubstring(userTs, "fnB()"));
|
||||
const response = executeSessionRequest<ts.server.protocol.DefinitionRequest, ts.server.protocol.DefinitionResponse>(session, ts.server.CommandNames.Definition, protocolFileLocationFromSubstring(userTs, "fnB()"));
|
||||
// bTs does not exist, so stick with bDts
|
||||
assert.deepEqual(response, [
|
||||
ts.projectSystem.protocolFileSpanWithContextFromSubstring({
|
||||
protocolFileSpanWithContextFromSubstring({
|
||||
file: bDts,
|
||||
text: "fnB",
|
||||
contextText: "export declare function fnB(): void;"
|
||||
@@ -290,12 +292,12 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
|
||||
it("navigateTo", () => {
|
||||
const session = makeSampleProjects();
|
||||
const response = ts.projectSystem.executeSessionRequest<ts.projectSystem.protocol.NavtoRequest, ts.projectSystem.protocol.NavtoResponse>(session, ts.projectSystem.CommandNames.Navto, { file: userTs.path, searchValue: "fn" });
|
||||
assert.deepEqual<readonly ts.projectSystem.protocol.NavtoItem[] | undefined>(response, [
|
||||
const response = executeSessionRequest<ts.server.protocol.NavtoRequest, ts.server.protocol.NavtoResponse>(session, ts.server.CommandNames.Navto, { file: userTs.path, searchValue: "fn" });
|
||||
assert.deepEqual<readonly ts.server.protocol.NavtoItem[] | undefined>(response, [
|
||||
// Keep the .d.ts file since the .ts file no longer exists
|
||||
// (otherwise it would be treated as not in the project)
|
||||
{
|
||||
...ts.projectSystem.protocolFileSpanFromSubstring({
|
||||
...protocolFileSpanFromSubstring({
|
||||
file: bDts,
|
||||
text: "export declare function fnB(): void;"
|
||||
}),
|
||||
@@ -306,7 +308,7 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
kindModifiers: "export,declare",
|
||||
},
|
||||
{
|
||||
...ts.projectSystem.protocolFileSpanFromSubstring({
|
||||
...protocolFileSpanFromSubstring({
|
||||
file: userTs,
|
||||
text: "export function fnUser() { a.fnA(); b.fnB(); a.instanceA; }"
|
||||
}),
|
||||
@@ -323,10 +325,10 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
|
||||
it("navigateToAll -- when neither file nor project is specified", () => {
|
||||
const session = makeSampleProjects(/*addUserTsConfig*/ true, /*keepAllFiles*/ true);
|
||||
const response = ts.projectSystem.executeSessionRequest<ts.projectSystem.protocol.NavtoRequest, ts.projectSystem.protocol.NavtoResponse>(session, ts.projectSystem.CommandNames.Navto, { file: undefined, searchValue: "fn" });
|
||||
assert.deepEqual<readonly ts.projectSystem.protocol.NavtoItem[] | undefined>(response, [
|
||||
const response = executeSessionRequest<ts.server.protocol.NavtoRequest, ts.server.protocol.NavtoResponse>(session, ts.server.CommandNames.Navto, { file: undefined, searchValue: "fn" });
|
||||
assert.deepEqual<readonly ts.server.protocol.NavtoItem[] | undefined>(response, [
|
||||
{
|
||||
...ts.projectSystem.protocolFileSpanFromSubstring({
|
||||
...protocolFileSpanFromSubstring({
|
||||
file: bTs,
|
||||
text: "export function fnB() {}"
|
||||
}),
|
||||
@@ -337,7 +339,7 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
kindModifiers: "export",
|
||||
},
|
||||
{
|
||||
...ts.projectSystem.protocolFileSpanFromSubstring({
|
||||
...protocolFileSpanFromSubstring({
|
||||
file: aTs,
|
||||
text: "export function fnA() {}"
|
||||
}),
|
||||
@@ -348,7 +350,7 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
kindModifiers: "export",
|
||||
},
|
||||
{
|
||||
...ts.projectSystem.protocolFileSpanFromSubstring({
|
||||
...protocolFileSpanFromSubstring({
|
||||
file: userTs,
|
||||
text: "export function fnUser() { a.fnA(); b.fnB(); a.instanceA; }"
|
||||
}),
|
||||
@@ -363,10 +365,10 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
|
||||
it("navigateToAll -- when file is not specified but project is", () => {
|
||||
const session = makeSampleProjects(/*addUserTsConfig*/ true, /*keepAllFiles*/ true);
|
||||
const response = ts.projectSystem.executeSessionRequest<ts.projectSystem.protocol.NavtoRequest, ts.projectSystem.protocol.NavtoResponse>(session, ts.projectSystem.CommandNames.Navto, { projectFileName: bTsconfig.path, file: undefined, searchValue: "fn" });
|
||||
assert.deepEqual<readonly ts.projectSystem.protocol.NavtoItem[] | undefined>(response, [
|
||||
const response = executeSessionRequest<ts.server.protocol.NavtoRequest, ts.server.protocol.NavtoResponse>(session, ts.server.CommandNames.Navto, { projectFileName: bTsconfig.path, file: undefined, searchValue: "fn" });
|
||||
assert.deepEqual<readonly ts.server.protocol.NavtoItem[] | undefined>(response, [
|
||||
{
|
||||
...ts.projectSystem.protocolFileSpanFromSubstring({
|
||||
...protocolFileSpanFromSubstring({
|
||||
file: bTs,
|
||||
text: "export function fnB() {}"
|
||||
}),
|
||||
@@ -379,7 +381,7 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
]);
|
||||
});
|
||||
|
||||
const referenceATs = (aTs: ts.projectSystem.File, isDefinition: true | undefined): ts.projectSystem.protocol.ReferencesResponseItem => ts.projectSystem.makeReferenceItem({
|
||||
const referenceATs = (aTs: File, isDefinition: true | undefined): ts.server.protocol.ReferencesResponseItem => makeReferenceItem({
|
||||
file: aTs,
|
||||
isDefinition,
|
||||
isWriteAccess: true,
|
||||
@@ -387,8 +389,8 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
contextText: "export function fnA() {}",
|
||||
lineText: "export function fnA() {}"
|
||||
});
|
||||
const referencesUserTs = (userTs: ts.projectSystem.File, isDefinition: false | undefined): readonly ts.projectSystem.protocol.ReferencesResponseItem[] => [
|
||||
ts.projectSystem.makeReferenceItem({
|
||||
const referencesUserTs = (userTs: File, isDefinition: false | undefined): readonly ts.server.protocol.ReferencesResponseItem[] => [
|
||||
makeReferenceItem({
|
||||
file: userTs,
|
||||
isDefinition,
|
||||
text: "fnA",
|
||||
@@ -399,11 +401,11 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
it("findAllReferences", () => {
|
||||
const session = makeSampleProjects();
|
||||
|
||||
const response = ts.projectSystem.executeSessionRequest<ts.projectSystem.protocol.ReferencesRequest, ts.projectSystem.protocol.ReferencesResponse>(session, ts.projectSystem.protocol.CommandTypes.References, ts.projectSystem.protocolFileLocationFromSubstring(userTs, "fnA()"));
|
||||
assert.deepEqual<ts.projectSystem.protocol.ReferencesResponseBody | undefined>(response, {
|
||||
const response = executeSessionRequest<ts.server.protocol.ReferencesRequest, ts.server.protocol.ReferencesResponse>(session, ts.server.protocol.CommandTypes.References, protocolFileLocationFromSubstring(userTs, "fnA()"));
|
||||
assert.deepEqual<ts.server.protocol.ReferencesResponseBody | undefined>(response, {
|
||||
refs: [...referencesUserTs(userTs, /*isDefinition*/ undefined), referenceATs(aTs, /*isDefinition*/ undefined)],
|
||||
symbolName: "fnA",
|
||||
symbolStartOffset: ts.projectSystem.protocolLocationFromSubstring(userTs.content, "fnA()").offset,
|
||||
symbolStartOffset: protocolLocationFromSubstring(userTs.content, "fnA()").offset,
|
||||
symbolDisplayString: "function fnA(): void",
|
||||
});
|
||||
|
||||
@@ -412,24 +414,24 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
|
||||
it("findAllReferences -- starting at definition", () => {
|
||||
const session = makeSampleProjects();
|
||||
ts.projectSystem.openFilesForSession([aTs], session); // If it's not opened, the reference isn't found.
|
||||
const response = ts.projectSystem.executeSessionRequest<ts.projectSystem.protocol.ReferencesRequest, ts.projectSystem.protocol.ReferencesResponse>(session, ts.projectSystem.protocol.CommandTypes.References, ts.projectSystem.protocolFileLocationFromSubstring(aTs, "fnA"));
|
||||
assert.deepEqual<ts.projectSystem.protocol.ReferencesResponseBody | undefined>(response, {
|
||||
openFilesForSession([aTs], session); // If it's not opened, the reference isn't found.
|
||||
const response = executeSessionRequest<ts.server.protocol.ReferencesRequest, ts.server.protocol.ReferencesResponse>(session, ts.server.protocol.CommandTypes.References, protocolFileLocationFromSubstring(aTs, "fnA"));
|
||||
assert.deepEqual<ts.server.protocol.ReferencesResponseBody | undefined>(response, {
|
||||
refs: [referenceATs(aTs, /*isDefinition*/ true), ...referencesUserTs(userTs, /*isDefinition*/ false)],
|
||||
symbolName: "fnA",
|
||||
symbolStartOffset: ts.projectSystem.protocolLocationFromSubstring(aTs.content, "fnA").offset,
|
||||
symbolStartOffset: protocolLocationFromSubstring(aTs.content, "fnA").offset,
|
||||
symbolDisplayString: "function fnA(): void",
|
||||
});
|
||||
verifyATsConfigWhenOpened(session);
|
||||
});
|
||||
|
||||
interface ReferencesFullRequest extends ts.projectSystem.protocol.FileLocationRequest { readonly command: ts.projectSystem.protocol.CommandTypes.ReferencesFull; }
|
||||
interface ReferencesFullResponse extends ts.projectSystem.protocol.Response { readonly body: readonly ts.ReferencedSymbol[]; }
|
||||
interface ReferencesFullRequest extends ts.server.protocol.FileLocationRequest { readonly command: ts.server.protocol.CommandTypes.ReferencesFull; }
|
||||
interface ReferencesFullResponse extends ts.server.protocol.Response { readonly body: readonly ts.ReferencedSymbol[]; }
|
||||
|
||||
it("findAllReferencesFull", () => {
|
||||
const session = makeSampleProjects();
|
||||
|
||||
const responseFull = ts.projectSystem.executeSessionRequest<ReferencesFullRequest, ReferencesFullResponse>(session, ts.projectSystem.protocol.CommandTypes.ReferencesFull, ts.projectSystem.protocolFileLocationFromSubstring(userTs, "fnA()"));
|
||||
const responseFull = executeSessionRequest<ReferencesFullRequest, ReferencesFullResponse>(session, ts.server.protocol.CommandTypes.ReferencesFull, protocolFileLocationFromSubstring(userTs, "fnA()"));
|
||||
|
||||
assert.deepEqual<readonly ts.ReferencedSymbol[]>(responseFull, [
|
||||
{
|
||||
@@ -464,25 +466,25 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
});
|
||||
|
||||
it("findAllReferencesFull definition is in mapped file", () => {
|
||||
const aTs: ts.projectSystem.File = { path: "/a/a.ts", content: `function f() {}` };
|
||||
const aTsconfig: ts.projectSystem.File = {
|
||||
const aTs: File = { path: "/a/a.ts", content: `function f() {}` };
|
||||
const aTsconfig: File = {
|
||||
path: "/a/tsconfig.json",
|
||||
content: JSON.stringify({ compilerOptions: { declaration: true, declarationMap: true, outFile: "../bin/a.js" } }),
|
||||
};
|
||||
const bTs: ts.projectSystem.File = { path: "/b/b.ts", content: `f();` };
|
||||
const bTsconfig: ts.projectSystem.File = { path: "/b/tsconfig.json", content: JSON.stringify({ references: [{ path: "../a" }] }) };
|
||||
const aDts: ts.projectSystem.File = { path: "/bin/a.d.ts", content: `declare function f(): void;\n//# sourceMappingURL=a.d.ts.map` };
|
||||
const aDtsMap: ts.projectSystem.File = {
|
||||
const bTs: File = { path: "/b/b.ts", content: `f();` };
|
||||
const bTsconfig: File = { path: "/b/tsconfig.json", content: JSON.stringify({ references: [{ path: "../a" }] }) };
|
||||
const aDts: File = { path: "/bin/a.d.ts", content: `declare function f(): void;\n//# sourceMappingURL=a.d.ts.map` };
|
||||
const aDtsMap: File = {
|
||||
path: "/bin/a.d.ts.map",
|
||||
content: JSON.stringify({ version: 3, file: "a.d.ts", sourceRoot: "", sources: ["../a/a.ts"], names: [], mappings: "AAAA,iBAAS,CAAC,SAAK" }),
|
||||
};
|
||||
|
||||
const session = ts.projectSystem.createSession(ts.projectSystem.createServerHost([aTs, aTsconfig, bTs, bTsconfig, aDts, aDtsMap]));
|
||||
const session = createSession(createServerHost([aTs, aTsconfig, bTs, bTsconfig, aDts, aDtsMap]));
|
||||
checkDeclarationFiles(aTs, session, [aDtsMap, aDts]);
|
||||
ts.projectSystem.openFilesForSession([bTs], session);
|
||||
ts.projectSystem.checkNumberOfProjects(session.getProjectService(), { configuredProjects: 2 }); // configured project of b is alive since a references b
|
||||
openFilesForSession([bTs], session);
|
||||
checkNumberOfProjects(session.getProjectService(), { configuredProjects: 2 }); // configured project of b is alive since a references b
|
||||
|
||||
const responseFull = ts.projectSystem.executeSessionRequest<ReferencesFullRequest, ReferencesFullResponse>(session, ts.projectSystem.protocol.CommandTypes.ReferencesFull, ts.projectSystem.protocolFileLocationFromSubstring(bTs, "f()"));
|
||||
const responseFull = executeSessionRequest<ReferencesFullRequest, ReferencesFullResponse>(session, ts.server.protocol.CommandTypes.ReferencesFull, protocolFileLocationFromSubstring(bTs, "f()"));
|
||||
|
||||
assert.deepEqual<readonly ts.ReferencedSymbol[]>(responseFull, [
|
||||
{
|
||||
@@ -530,43 +532,43 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
it("findAllReferences -- target does not exist", () => {
|
||||
const session = makeSampleProjects();
|
||||
|
||||
const response = ts.projectSystem.executeSessionRequest<ts.projectSystem.protocol.ReferencesRequest, ts.projectSystem.protocol.ReferencesResponse>(session, ts.projectSystem.protocol.CommandTypes.References, ts.projectSystem.protocolFileLocationFromSubstring(userTs, "fnB()"));
|
||||
assert.deepEqual<ts.projectSystem.protocol.ReferencesResponseBody | undefined>(response, {
|
||||
const response = executeSessionRequest<ts.server.protocol.ReferencesRequest, ts.server.protocol.ReferencesResponse>(session, ts.server.protocol.CommandTypes.References, protocolFileLocationFromSubstring(userTs, "fnB()"));
|
||||
assert.deepEqual<ts.server.protocol.ReferencesResponseBody | undefined>(response, {
|
||||
refs: [
|
||||
ts.projectSystem.makeReferenceItem({
|
||||
makeReferenceItem({
|
||||
file: bDts,
|
||||
isWriteAccess: true,
|
||||
text: "fnB",
|
||||
contextText: "export declare function fnB(): void;",
|
||||
lineText: "export declare function fnB(): void;"
|
||||
}),
|
||||
ts.projectSystem.makeReferenceItem({
|
||||
makeReferenceItem({
|
||||
file: userTs,
|
||||
text: "fnB",
|
||||
lineText: "export function fnUser() { a.fnA(); b.fnB(); a.instanceA; }"
|
||||
}),
|
||||
],
|
||||
symbolName: "fnB",
|
||||
symbolStartOffset: ts.projectSystem.protocolLocationFromSubstring(userTs.content, "fnB()").offset,
|
||||
symbolStartOffset: protocolLocationFromSubstring(userTs.content, "fnB()").offset,
|
||||
symbolDisplayString: "function fnB(): void",
|
||||
});
|
||||
verifySingleInferredProject(session);
|
||||
});
|
||||
|
||||
const renameATs = (aTs: ts.projectSystem.File): ts.projectSystem.protocol.SpanGroup => ({
|
||||
const renameATs = (aTs: File): ts.server.protocol.SpanGroup => ({
|
||||
file: aTs.path,
|
||||
locs: [
|
||||
ts.projectSystem.protocolRenameSpanFromSubstring({
|
||||
protocolRenameSpanFromSubstring({
|
||||
fileText: aTs.content,
|
||||
text: "fnA",
|
||||
contextText: "export function fnA() {}"
|
||||
})
|
||||
],
|
||||
});
|
||||
const renameUserTs = (userTs: ts.projectSystem.File): ts.projectSystem.protocol.SpanGroup => ({
|
||||
const renameUserTs = (userTs: File): ts.server.protocol.SpanGroup => ({
|
||||
file: userTs.path,
|
||||
locs: [
|
||||
ts.projectSystem.protocolRenameSpanFromSubstring({
|
||||
protocolRenameSpanFromSubstring({
|
||||
fileText: userTs.content,
|
||||
text: "fnA"
|
||||
})
|
||||
@@ -575,8 +577,8 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
|
||||
it("renameLocations", () => {
|
||||
const session = makeSampleProjects();
|
||||
const response = ts.projectSystem.executeSessionRequest<ts.projectSystem.protocol.RenameRequest, ts.projectSystem.protocol.RenameResponse>(session, ts.projectSystem.protocol.CommandTypes.Rename, ts.projectSystem.protocolFileLocationFromSubstring(userTs, "fnA()"));
|
||||
assert.deepEqual<ts.projectSystem.protocol.RenameResponseBody | undefined>(response, {
|
||||
const response = executeSessionRequest<ts.server.protocol.RenameRequest, ts.server.protocol.RenameResponse>(session, ts.server.protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(userTs, "fnA()"));
|
||||
assert.deepEqual<ts.server.protocol.RenameResponseBody | undefined>(response, {
|
||||
info: {
|
||||
canRename: true,
|
||||
displayName: "fnA",
|
||||
@@ -584,7 +586,7 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
fullDisplayName: '"/a/bin/a".fnA', // Ideally this would use the original source's path instead of the declaration file's path.
|
||||
kind: ts.ScriptElementKind.functionElement,
|
||||
kindModifiers: [ts.ScriptElementKindModifier.exportedModifier, ts.ScriptElementKindModifier.ambientModifier].join(","),
|
||||
triggerSpan: ts.projectSystem.protocolTextSpanFromSubstring(userTs.content, "fnA"),
|
||||
triggerSpan: protocolTextSpanFromSubstring(userTs.content, "fnA"),
|
||||
},
|
||||
locs: [renameUserTs(userTs), renameATs(aTs)],
|
||||
});
|
||||
@@ -593,9 +595,9 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
|
||||
it("renameLocations -- starting at definition", () => {
|
||||
const session = makeSampleProjects();
|
||||
ts.projectSystem.openFilesForSession([aTs], session); // If it's not opened, the reference isn't found.
|
||||
const response = ts.projectSystem.executeSessionRequest<ts.projectSystem.protocol.RenameRequest, ts.projectSystem.protocol.RenameResponse>(session, ts.projectSystem.protocol.CommandTypes.Rename, ts.projectSystem.protocolFileLocationFromSubstring(aTs, "fnA"));
|
||||
assert.deepEqual<ts.projectSystem.protocol.RenameResponseBody | undefined>(response, {
|
||||
openFilesForSession([aTs], session); // If it's not opened, the reference isn't found.
|
||||
const response = executeSessionRequest<ts.server.protocol.RenameRequest, ts.server.protocol.RenameResponse>(session, ts.server.protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(aTs, "fnA"));
|
||||
assert.deepEqual<ts.server.protocol.RenameResponseBody | undefined>(response, {
|
||||
info: {
|
||||
canRename: true,
|
||||
displayName: "fnA",
|
||||
@@ -603,7 +605,7 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
fullDisplayName: '"/a/a".fnA',
|
||||
kind: ts.ScriptElementKind.functionElement,
|
||||
kindModifiers: ts.ScriptElementKindModifier.exportedModifier,
|
||||
triggerSpan: ts.projectSystem.protocolTextSpanFromSubstring(aTs.content, "fnA"),
|
||||
triggerSpan: protocolTextSpanFromSubstring(aTs.content, "fnA"),
|
||||
},
|
||||
locs: [renameATs(aTs), renameUserTs(userTs)],
|
||||
});
|
||||
@@ -612,7 +614,7 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
|
||||
it("renameLocationsFull", () => {
|
||||
const session = makeSampleProjects();
|
||||
const response = ts.projectSystem.executeSessionRequest<ts.projectSystem.protocol.RenameFullRequest, ts.projectSystem.protocol.RenameFullResponse>(session, ts.projectSystem.protocol.CommandTypes.RenameLocationsFull, ts.projectSystem.protocolFileLocationFromSubstring(userTs, "fnA()"));
|
||||
const response = executeSessionRequest<ts.server.protocol.RenameFullRequest, ts.server.protocol.RenameFullResponse>(session, ts.server.protocol.CommandTypes.RenameLocationsFull, protocolFileLocationFromSubstring(userTs, "fnA()"));
|
||||
assert.deepEqual<readonly ts.RenameLocation[]>(response, [
|
||||
renameLocation({ file: userTs, text: "fnA" }),
|
||||
renameLocation({ file: aTs, text: "fnA", contextText: "export function fnA() {}" }),
|
||||
@@ -622,8 +624,8 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
|
||||
it("renameLocations -- target does not exist", () => {
|
||||
const session = makeSampleProjects();
|
||||
const response = ts.projectSystem.executeSessionRequest<ts.projectSystem.protocol.RenameRequest, ts.projectSystem.protocol.RenameResponse>(session, ts.projectSystem.protocol.CommandTypes.Rename, ts.projectSystem.protocolFileLocationFromSubstring(userTs, "fnB()"));
|
||||
assert.deepEqual<ts.projectSystem.protocol.RenameResponseBody | undefined>(response, {
|
||||
const response = executeSessionRequest<ts.server.protocol.RenameRequest, ts.server.protocol.RenameResponse>(session, ts.server.protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(userTs, "fnB()"));
|
||||
assert.deepEqual<ts.server.protocol.RenameResponseBody | undefined>(response, {
|
||||
info: {
|
||||
canRename: true,
|
||||
displayName: "fnB",
|
||||
@@ -631,13 +633,13 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
fullDisplayName: '"/b/bin/b".fnB',
|
||||
kind: ts.ScriptElementKind.functionElement,
|
||||
kindModifiers: [ts.ScriptElementKindModifier.exportedModifier, ts.ScriptElementKindModifier.ambientModifier].join(","),
|
||||
triggerSpan: ts.projectSystem.protocolTextSpanFromSubstring(userTs.content, "fnB"),
|
||||
triggerSpan: protocolTextSpanFromSubstring(userTs.content, "fnB"),
|
||||
},
|
||||
locs: [
|
||||
{
|
||||
file: bDts.path,
|
||||
locs: [
|
||||
ts.projectSystem.protocolRenameSpanFromSubstring({
|
||||
protocolRenameSpanFromSubstring({
|
||||
fileText: bDts.content,
|
||||
text: "fnB",
|
||||
contextText: "export declare function fnB(): void;"
|
||||
@@ -647,7 +649,7 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
{
|
||||
file: userTs.path,
|
||||
locs: [
|
||||
ts.projectSystem.protocolRenameSpanFromSubstring({
|
||||
protocolRenameSpanFromSubstring({
|
||||
fileText: userTs.content,
|
||||
text: "fnB"
|
||||
})
|
||||
@@ -660,15 +662,15 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
|
||||
it("getEditsForFileRename", () => {
|
||||
const session = makeSampleProjects();
|
||||
const response = ts.projectSystem.executeSessionRequest<ts.projectSystem.protocol.GetEditsForFileRenameRequest, ts.projectSystem.protocol.GetEditsForFileRenameResponse>(session, ts.projectSystem.protocol.CommandTypes.GetEditsForFileRename, {
|
||||
const response = executeSessionRequest<ts.server.protocol.GetEditsForFileRenameRequest, ts.server.protocol.GetEditsForFileRenameResponse>(session, ts.server.protocol.CommandTypes.GetEditsForFileRename, {
|
||||
oldFilePath: aTs.path,
|
||||
newFilePath: "/a/aNew.ts",
|
||||
});
|
||||
assert.deepEqual<readonly ts.projectSystem.protocol.FileCodeEdits[]>(response, [
|
||||
assert.deepEqual<readonly ts.server.protocol.FileCodeEdits[]>(response, [
|
||||
{
|
||||
fileName: userTs.path,
|
||||
textChanges: [
|
||||
{ ...ts.projectSystem.protocolTextSpanFromSubstring(userTs.content, "../a/bin/a"), newText: "../a/bin/aNew" },
|
||||
{ ...protocolTextSpanFromSubstring(userTs.content, "../a/bin/a"), newText: "../a/bin/aNew" },
|
||||
],
|
||||
},
|
||||
]);
|
||||
@@ -676,8 +678,8 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
});
|
||||
|
||||
it("getEditsForFileRename when referencing project doesnt include file and its renamed", () => {
|
||||
const aTs: ts.projectSystem.File = { path: "/a/src/a.ts", content: "" };
|
||||
const aTsconfig: ts.projectSystem.File = {
|
||||
const aTs: File = { path: "/a/src/a.ts", content: "" };
|
||||
const aTsconfig: File = {
|
||||
path: "/a/tsconfig.json",
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
@@ -688,8 +690,8 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
}
|
||||
}),
|
||||
};
|
||||
const bTs: ts.projectSystem.File = { path: "/b/src/b.ts", content: "" };
|
||||
const bTsconfig: ts.projectSystem.File = {
|
||||
const bTs: File = { path: "/b/src/b.ts", content: "" };
|
||||
const bTsconfig: File = {
|
||||
path: "/b/tsconfig.json",
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
@@ -701,14 +703,14 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
}),
|
||||
};
|
||||
|
||||
const host = ts.projectSystem.createServerHost([aTs, aTsconfig, bTs, bTsconfig]);
|
||||
const session = ts.projectSystem.createSession(host);
|
||||
ts.projectSystem.openFilesForSession([aTs, bTs], session);
|
||||
const response = ts.projectSystem.executeSessionRequest<ts.projectSystem.protocol.GetEditsForFileRenameRequest, ts.projectSystem.protocol.GetEditsForFileRenameResponse>(session, ts.projectSystem.CommandNames.GetEditsForFileRename, {
|
||||
const host = createServerHost([aTs, aTsconfig, bTs, bTsconfig]);
|
||||
const session = createSession(host);
|
||||
openFilesForSession([aTs, bTs], session);
|
||||
const response = executeSessionRequest<ts.server.protocol.GetEditsForFileRenameRequest, ts.server.protocol.GetEditsForFileRenameResponse>(session, ts.server.CommandNames.GetEditsForFileRename, {
|
||||
oldFilePath: aTs.path,
|
||||
newFilePath: "/a/src/a1.ts",
|
||||
});
|
||||
assert.deepEqual<readonly ts.projectSystem.protocol.FileCodeEdits[]>(response, []); // Should not change anything
|
||||
assert.deepEqual<readonly ts.server.protocol.FileCodeEdits[]>(response, []); // Should not change anything
|
||||
});
|
||||
|
||||
it("does not jump to source if inlined sources", () => {
|
||||
@@ -716,29 +718,29 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
...aDtsMapContent,
|
||||
sourcesContent: [aTs.content]
|
||||
};
|
||||
const aDtsMapInlinedSources: ts.projectSystem.File = {
|
||||
const aDtsMapInlinedSources: File = {
|
||||
path: aDtsMap.path,
|
||||
content: JSON.stringify(aDtsInlinedSources)
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([aTs, aDtsMapInlinedSources, aDts, bTs, bDtsMap, bDts, userTs, dummyFile]);
|
||||
const session = ts.projectSystem.createSession(host);
|
||||
const host = createServerHost([aTs, aDtsMapInlinedSources, aDts, bTs, bDtsMap, bDts, userTs, dummyFile]);
|
||||
const session = createSession(host);
|
||||
|
||||
ts.projectSystem.openFilesForSession([userTs], session);
|
||||
openFilesForSession([userTs], session);
|
||||
const service = session.getProjectService();
|
||||
// If config file then userConfig project and bConfig project since it is referenced
|
||||
ts.projectSystem.checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
|
||||
// Inlined so does not jump to aTs
|
||||
assert.deepEqual(
|
||||
ts.projectSystem.executeSessionRequest<ts.projectSystem.protocol.DefinitionAndBoundSpanRequest, ts.projectSystem.protocol.DefinitionAndBoundSpanResponse>(
|
||||
executeSessionRequest<ts.server.protocol.DefinitionAndBoundSpanRequest, ts.server.protocol.DefinitionAndBoundSpanResponse>(
|
||||
session,
|
||||
ts.projectSystem.protocol.CommandTypes.DefinitionAndBoundSpan,
|
||||
ts.projectSystem.protocolFileLocationFromSubstring(userTs, "fnA()")
|
||||
ts.server.protocol.CommandTypes.DefinitionAndBoundSpan,
|
||||
protocolFileLocationFromSubstring(userTs, "fnA()")
|
||||
),
|
||||
{
|
||||
textSpan: ts.projectSystem.protocolTextSpanFromSubstring(userTs.content, "fnA"),
|
||||
textSpan: protocolTextSpanFromSubstring(userTs.content, "fnA"),
|
||||
definitions: [
|
||||
ts.projectSystem.protocolFileSpanWithContextFromSubstring({
|
||||
protocolFileSpanWithContextFromSubstring({
|
||||
file: aDts,
|
||||
text: "fnA",
|
||||
contextText: "export declare function fnA(): void;"
|
||||
@@ -749,15 +751,15 @@ describe("unittests:: tsserver:: with declaration file maps:: project references
|
||||
|
||||
// Not inlined, jumps to bTs
|
||||
assert.deepEqual(
|
||||
ts.projectSystem.executeSessionRequest<ts.projectSystem.protocol.DefinitionAndBoundSpanRequest, ts.projectSystem.protocol.DefinitionAndBoundSpanResponse>(
|
||||
executeSessionRequest<ts.server.protocol.DefinitionAndBoundSpanRequest, ts.server.protocol.DefinitionAndBoundSpanResponse>(
|
||||
session,
|
||||
ts.projectSystem.protocol.CommandTypes.DefinitionAndBoundSpan,
|
||||
ts.projectSystem.protocolFileLocationFromSubstring(userTs, "fnB()")
|
||||
ts.server.protocol.CommandTypes.DefinitionAndBoundSpan,
|
||||
protocolFileLocationFromSubstring(userTs, "fnB()")
|
||||
),
|
||||
{
|
||||
textSpan: ts.projectSystem.protocolTextSpanFromSubstring(userTs.content, "fnB"),
|
||||
textSpan: protocolTextSpanFromSubstring(userTs.content, "fnB"),
|
||||
definitions: [
|
||||
ts.projectSystem.protocolFileSpanWithContextFromSubstring({
|
||||
protocolFileSpanWithContextFromSubstring({
|
||||
file: bTs,
|
||||
text: "fnB",
|
||||
contextText: "export function fnB() {}"
|
||||
|
||||
@@ -1,29 +1,31 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { createServerHost, File, libFile } from "../virtualFileSystemWithWatch";
|
||||
import { TestProjectService, checkProjectActualFiles, createProjectService } from "./helpers";
|
||||
|
||||
describe("unittests:: tsserver:: document registry in project service", () => {
|
||||
const importModuleContent = `import {a} from "./module1"`;
|
||||
const file: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/index.ts`,
|
||||
const file: File = {
|
||||
path: `/user/username/projects/myproject/index.ts`,
|
||||
content: importModuleContent
|
||||
};
|
||||
const moduleFile: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/module1.d.ts`,
|
||||
const moduleFile: File = {
|
||||
path: `/user/username/projects/myproject/module1.d.ts`,
|
||||
content: "export const a: number;"
|
||||
};
|
||||
const configFile: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const configFile: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: JSON.stringify({ files: ["index.ts"] })
|
||||
};
|
||||
|
||||
function getProject(service: ts.projectSystem.TestProjectService) {
|
||||
function getProject(service: TestProjectService) {
|
||||
return service.configuredProjects.get(configFile.path)!;
|
||||
}
|
||||
|
||||
function checkProject(service: ts.projectSystem.TestProjectService, moduleIsOrphan: boolean) {
|
||||
function checkProject(service: TestProjectService, moduleIsOrphan: boolean) {
|
||||
// Update the project
|
||||
const project = getProject(service);
|
||||
project.getLanguageService();
|
||||
ts.projectSystem.checkProjectActualFiles(project, [file.path, ts.projectSystem.libFile.path, configFile.path, ...(moduleIsOrphan ? [] : [moduleFile.path])]);
|
||||
checkProjectActualFiles(project, [file.path, libFile.path, configFile.path, ...(moduleIsOrphan ? [] : [moduleFile.path])]);
|
||||
const moduleInfo = service.getScriptInfo(moduleFile.path)!;
|
||||
assert.isDefined(moduleInfo);
|
||||
assert.equal(moduleInfo.isOrphan(), moduleIsOrphan);
|
||||
@@ -32,20 +34,20 @@ describe("unittests:: tsserver:: document registry in project service", () => {
|
||||
}
|
||||
|
||||
function createServiceAndHost() {
|
||||
const host = ts.projectSystem.createServerHost([file, moduleFile, ts.projectSystem.libFile, configFile]);
|
||||
const service = ts.projectSystem.createProjectService(host);
|
||||
const host = createServerHost([file, moduleFile, libFile, configFile]);
|
||||
const service = createProjectService(host);
|
||||
service.openClientFile(file.path);
|
||||
checkProject(service, /*moduleIsOrphan*/ false);
|
||||
return { host, service };
|
||||
}
|
||||
|
||||
function changeFileToNotImportModule(service: ts.projectSystem.TestProjectService) {
|
||||
function changeFileToNotImportModule(service: TestProjectService) {
|
||||
const info = service.getScriptInfo(file.path)!;
|
||||
service.applyChangesToFile(info, ts.singleIterator({ span: { start: 0, length: importModuleContent.length }, newText: "" }));
|
||||
checkProject(service, /*moduleIsOrphan*/ true);
|
||||
}
|
||||
|
||||
function changeFileToImportModule(service: ts.projectSystem.TestProjectService) {
|
||||
function changeFileToImportModule(service: TestProjectService) {
|
||||
const info = service.getScriptInfo(file.path)!;
|
||||
service.applyChangesToFile(info, ts.singleIterator({ span: { start: 0, length: 0 }, newText: importModuleContent }));
|
||||
checkProject(service, /*moduleIsOrphan*/ false);
|
||||
|
||||
@@ -1,30 +1,32 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { createServerHost, File } from "../virtualFileSystemWithWatch";
|
||||
import { createSession, openFilesForSession, executeSessionRequest } from "./helpers";
|
||||
|
||||
describe("unittests:: tsserver:: duplicate packages", () => {
|
||||
// Tests that 'moduleSpecifiers.ts' will import from the redirecting file, and not from the file it redirects to, if that can provide a global module specifier.
|
||||
it("works with import fixes", () => {
|
||||
const packageContent = "export const foo: number;";
|
||||
const packageJsonContent = JSON.stringify({ name: "foo", version: "1.2.3" });
|
||||
const aFooIndex: ts.projectSystem.File = { path: "/a/node_modules/foo/index.d.ts", content: packageContent };
|
||||
const aFooPackage: ts.projectSystem.File = { path: "/a/node_modules/foo/package.json", content: packageJsonContent };
|
||||
const bFooIndex: ts.projectSystem.File = { path: "/b/node_modules/foo/index.d.ts", content: packageContent };
|
||||
const bFooPackage: ts.projectSystem.File = { path: "/b/node_modules/foo/package.json", content: packageJsonContent };
|
||||
const aFooIndex: File = { path: "/a/node_modules/foo/index.d.ts", content: packageContent };
|
||||
const aFooPackage: File = { path: "/a/node_modules/foo/package.json", content: packageJsonContent };
|
||||
const bFooIndex: File = { path: "/b/node_modules/foo/index.d.ts", content: packageContent };
|
||||
const bFooPackage: File = { path: "/b/node_modules/foo/package.json", content: packageJsonContent };
|
||||
|
||||
const userContent = 'import("foo");\nfoo';
|
||||
const aUser: ts.projectSystem.File = { path: "/a/user.ts", content: userContent };
|
||||
const bUser: ts.projectSystem.File = { path: "/b/user.ts", content: userContent };
|
||||
const tsconfig: ts.projectSystem.File = {
|
||||
const aUser: File = { path: "/a/user.ts", content: userContent };
|
||||
const bUser: File = { path: "/b/user.ts", content: userContent };
|
||||
const tsconfig: File = {
|
||||
path: "/tsconfig.json",
|
||||
content: "{}",
|
||||
};
|
||||
|
||||
const host = ts.projectSystem.createServerHost([aFooIndex, aFooPackage, bFooIndex, bFooPackage, aUser, bUser, tsconfig]);
|
||||
const session = ts.projectSystem.createSession(host);
|
||||
const host = createServerHost([aFooIndex, aFooPackage, bFooIndex, bFooPackage, aUser, bUser, tsconfig]);
|
||||
const session = createSession(host);
|
||||
|
||||
ts.projectSystem.openFilesForSession([aUser, bUser], session);
|
||||
openFilesForSession([aUser, bUser], session);
|
||||
|
||||
for (const user of [aUser, bUser]) {
|
||||
const response = ts.projectSystem.executeSessionRequest<ts.projectSystem.protocol.CodeFixRequest, ts.projectSystem.protocol.CodeFixResponse>(session, ts.projectSystem.protocol.CommandTypes.GetCodeFixes, {
|
||||
const response = executeSessionRequest<ts.server.protocol.CodeFixRequest, ts.server.protocol.CodeFixResponse>(session, ts.server.protocol.CommandTypes.GetCodeFixes, {
|
||||
file: user.path,
|
||||
startLine: 2,
|
||||
startOffset: 1,
|
||||
@@ -32,7 +34,7 @@ describe("unittests:: tsserver:: duplicate packages", () => {
|
||||
endOffset: 4,
|
||||
errorCodes: [ts.Diagnostics.Cannot_find_name_0.code],
|
||||
});
|
||||
assert.deepEqual<readonly ts.projectSystem.protocol.CodeFixAction[] | undefined>(response, [
|
||||
assert.deepEqual<readonly ts.server.protocol.CodeFixAction[] | undefined>(response, [
|
||||
{
|
||||
description: `Add import from "foo"`,
|
||||
fixName: "import",
|
||||
|
||||
@@ -1,41 +1,42 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { verifyDynamic } from "./helpers";
|
||||
import { createServerHost, File, libFile } from "../virtualFileSystemWithWatch";
|
||||
import { checkNumberOfProjects, checkProjectActualFiles, checkProjectRootFiles, createProjectService, createSession, executeSessionRequest, executeSessionRequestNoResponse, openFilesForSession, verifyDynamic } from "./helpers";
|
||||
|
||||
function verifyPathRecognizedAsDynamic(path: string) {
|
||||
const file: ts.projectSystem.File = {
|
||||
const file: File = {
|
||||
path,
|
||||
content: `/// <reference path="../../../../../../typings/@epic/Core.d.ts" />
|
||||
/// <reference path="../../../../../../typings/@epic/Shell.d.ts" />
|
||||
var x = 10;`
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([ts.projectSystem.libFile]);
|
||||
const projectService = ts.projectSystem.createProjectService(host);
|
||||
const host = createServerHost([libFile]);
|
||||
const projectService = createProjectService(host);
|
||||
projectService.openClientFile(file.path, file.content);
|
||||
verifyDynamic(projectService, projectService.toPath(file.path));
|
||||
|
||||
projectService.checkNumberOfProjects({ inferredProjects: 1 });
|
||||
const project = projectService.inferredProjects[0];
|
||||
ts.projectSystem.checkProjectRootFiles(project, [file.path]);
|
||||
ts.projectSystem.checkProjectActualFiles(project, [file.path, ts.projectSystem.libFile.path]);
|
||||
checkProjectRootFiles(project, [file.path]);
|
||||
checkProjectActualFiles(project, [file.path, libFile.path]);
|
||||
}
|
||||
|
||||
describe("unittests:: tsserver:: dynamicFiles:: Untitled files", () => {
|
||||
const untitledFile = "untitled:^Untitled-1";
|
||||
it("Can convert positions to locations", () => {
|
||||
const aTs: ts.projectSystem.File = { path: "/proj/a.ts", content: "" };
|
||||
const tsconfig: ts.projectSystem.File = { path: "/proj/tsconfig.json", content: "{}" };
|
||||
const session = ts.projectSystem.createSession(ts.projectSystem.createServerHost([aTs, tsconfig]), { useInferredProjectPerProjectRoot: true });
|
||||
const aTs: File = { path: "/proj/a.ts", content: "" };
|
||||
const tsconfig: File = { path: "/proj/tsconfig.json", content: "{}" };
|
||||
const session = createSession(createServerHost([aTs, tsconfig]), { useInferredProjectPerProjectRoot: true });
|
||||
|
||||
ts.projectSystem.openFilesForSession([aTs], session);
|
||||
openFilesForSession([aTs], session);
|
||||
|
||||
ts.projectSystem.executeSessionRequestNoResponse<ts.projectSystem.protocol.OpenRequest>(session, ts.projectSystem.protocol.CommandTypes.Open, {
|
||||
executeSessionRequestNoResponse<ts.server.protocol.OpenRequest>(session, ts.server.protocol.CommandTypes.Open, {
|
||||
file: untitledFile,
|
||||
fileContent: `/// <reference path="../../../../../../typings/@epic/Core.d.ts" />\nlet foo = 1;\nfooo/**/`,
|
||||
scriptKindName: "TS",
|
||||
projectRootPath: "/proj",
|
||||
});
|
||||
verifyDynamic(session.getProjectService(), `/proj/untitled:^untitled-1`);
|
||||
const response = ts.projectSystem.executeSessionRequest<ts.projectSystem.protocol.CodeFixRequest, ts.projectSystem.protocol.CodeFixResponse>(session, ts.projectSystem.protocol.CommandTypes.GetCodeFixes, {
|
||||
const response = executeSessionRequest<ts.server.protocol.CodeFixRequest, ts.server.protocol.CodeFixResponse>(session, ts.server.protocol.CommandTypes.GetCodeFixes, {
|
||||
file: untitledFile,
|
||||
startLine: 3,
|
||||
startOffset: 1,
|
||||
@@ -43,7 +44,7 @@ describe("unittests:: tsserver:: dynamicFiles:: Untitled files", () => {
|
||||
endOffset: 5,
|
||||
errorCodes: [ts.Diagnostics.Cannot_find_name_0_Did_you_mean_1.code],
|
||||
});
|
||||
assert.deepEqual<readonly ts.projectSystem.protocol.CodeFixAction[] | undefined>(response, [
|
||||
assert.deepEqual<readonly ts.server.protocol.CodeFixAction[] | undefined>(response, [
|
||||
{
|
||||
description: "Change spelling to 'foo'",
|
||||
fixName: "spelling",
|
||||
@@ -63,68 +64,68 @@ describe("unittests:: tsserver:: dynamicFiles:: Untitled files", () => {
|
||||
});
|
||||
|
||||
it("opening untitled files", () => {
|
||||
const config: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const config: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: "{}"
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([config, ts.projectSystem.libFile], { useCaseSensitiveFileNames: true, currentDirectory: ts.tscWatch.projectRoot });
|
||||
const service = ts.projectSystem.createProjectService(host);
|
||||
service.openClientFile(untitledFile, "const x = 10;", /*scriptKind*/ undefined, ts.tscWatch.projectRoot);
|
||||
ts.projectSystem.checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
ts.projectSystem.checkProjectActualFiles(service.inferredProjects[0], [untitledFile, ts.projectSystem.libFile.path]);
|
||||
verifyDynamic(service, `${ts.tscWatch.projectRoot}/${untitledFile}`);
|
||||
const host = createServerHost([config, libFile], { useCaseSensitiveFileNames: true, currentDirectory: "/user/username/projects/myproject" });
|
||||
const service = createProjectService(host);
|
||||
service.openClientFile(untitledFile, "const x = 10;", /*scriptKind*/ undefined, "/user/username/projects/myproject");
|
||||
checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
checkProjectActualFiles(service.inferredProjects[0], [untitledFile, libFile.path]);
|
||||
verifyDynamic(service, `/user/username/projects/myproject/${untitledFile}`);
|
||||
|
||||
const untitled: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/Untitled-1.ts`,
|
||||
const untitled: File = {
|
||||
path: `/user/username/projects/myproject/Untitled-1.ts`,
|
||||
content: "const x = 10;"
|
||||
};
|
||||
host.writeFile(untitled.path, untitled.content);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
service.openClientFile(untitled.path, untitled.content, /*scriptKind*/ undefined, ts.tscWatch.projectRoot);
|
||||
ts.projectSystem.checkNumberOfProjects(service, { configuredProjects: 1, inferredProjects: 1 });
|
||||
ts.projectSystem.checkProjectActualFiles(service.configuredProjects.get(config.path)!, [untitled.path, ts.projectSystem.libFile.path, config.path]);
|
||||
ts.projectSystem.checkProjectActualFiles(service.inferredProjects[0], [untitledFile, ts.projectSystem.libFile.path]);
|
||||
service.openClientFile(untitled.path, untitled.content, /*scriptKind*/ undefined, "/user/username/projects/myproject");
|
||||
checkNumberOfProjects(service, { configuredProjects: 1, inferredProjects: 1 });
|
||||
checkProjectActualFiles(service.configuredProjects.get(config.path)!, [untitled.path, libFile.path, config.path]);
|
||||
checkProjectActualFiles(service.inferredProjects[0], [untitledFile, libFile.path]);
|
||||
|
||||
service.closeClientFile(untitledFile);
|
||||
ts.projectSystem.checkProjectActualFiles(service.configuredProjects.get(config.path)!, [untitled.path, ts.projectSystem.libFile.path, config.path]);
|
||||
ts.projectSystem.checkProjectActualFiles(service.inferredProjects[0], [untitledFile, ts.projectSystem.libFile.path]);
|
||||
checkProjectActualFiles(service.configuredProjects.get(config.path)!, [untitled.path, libFile.path, config.path]);
|
||||
checkProjectActualFiles(service.inferredProjects[0], [untitledFile, libFile.path]);
|
||||
|
||||
service.openClientFile(untitledFile, "const x = 10;", /*scriptKind*/ undefined, ts.tscWatch.projectRoot);
|
||||
verifyDynamic(service, `${ts.tscWatch.projectRoot}/${untitledFile}`);
|
||||
ts.projectSystem.checkProjectActualFiles(service.configuredProjects.get(config.path)!, [untitled.path, ts.projectSystem.libFile.path, config.path]);
|
||||
ts.projectSystem.checkProjectActualFiles(service.inferredProjects[0], [untitledFile, ts.projectSystem.libFile.path]);
|
||||
service.openClientFile(untitledFile, "const x = 10;", /*scriptKind*/ undefined, "/user/username/projects/myproject");
|
||||
verifyDynamic(service, `/user/username/projects/myproject/${untitledFile}`);
|
||||
checkProjectActualFiles(service.configuredProjects.get(config.path)!, [untitled.path, libFile.path, config.path]);
|
||||
checkProjectActualFiles(service.inferredProjects[0], [untitledFile, libFile.path]);
|
||||
});
|
||||
|
||||
it("opening and closing untitled files when projectRootPath is different from currentDirectory", () => {
|
||||
const config: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const config: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: "{}"
|
||||
};
|
||||
const file: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/file.ts`,
|
||||
const file: File = {
|
||||
path: `/user/username/projects/myproject/file.ts`,
|
||||
content: "const y = 10"
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([config, file, ts.projectSystem.libFile], { useCaseSensitiveFileNames: true });
|
||||
const service = ts.projectSystem.createProjectService(host, { useInferredProjectPerProjectRoot: true });
|
||||
service.openClientFile(untitledFile, "const x = 10;", /*scriptKind*/ undefined, ts.tscWatch.projectRoot);
|
||||
ts.projectSystem.checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
ts.projectSystem.checkProjectActualFiles(service.inferredProjects[0], [untitledFile, ts.projectSystem.libFile.path]);
|
||||
verifyDynamic(service, `${ts.tscWatch.projectRoot}/${untitledFile}`);
|
||||
const host = createServerHost([config, file, libFile], { useCaseSensitiveFileNames: true });
|
||||
const service = createProjectService(host, { useInferredProjectPerProjectRoot: true });
|
||||
service.openClientFile(untitledFile, "const x = 10;", /*scriptKind*/ undefined, "/user/username/projects/myproject");
|
||||
checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
checkProjectActualFiles(service.inferredProjects[0], [untitledFile, libFile.path]);
|
||||
verifyDynamic(service, `/user/username/projects/myproject/${untitledFile}`);
|
||||
|
||||
// Close untitled file
|
||||
service.closeClientFile(untitledFile);
|
||||
|
||||
// Open file from configured project which should collect inferredProject
|
||||
service.openClientFile(file.path);
|
||||
ts.projectSystem.checkNumberOfProjects(service, { configuredProjects: 1 });
|
||||
checkNumberOfProjects(service, { configuredProjects: 1 });
|
||||
});
|
||||
|
||||
it("when changing scriptKind of the untitled files", () => {
|
||||
const host = ts.projectSystem.createServerHost([ts.projectSystem.libFile], { useCaseSensitiveFileNames: true });
|
||||
const service = ts.projectSystem.createProjectService(host, { useInferredProjectPerProjectRoot: true });
|
||||
service.openClientFile(untitledFile, "const x = 10;", ts.ScriptKind.TS, ts.tscWatch.projectRoot);
|
||||
ts.projectSystem.checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
ts.projectSystem.checkProjectActualFiles(service.inferredProjects[0], [untitledFile, ts.projectSystem.libFile.path]);
|
||||
const host = createServerHost([libFile], { useCaseSensitiveFileNames: true });
|
||||
const service = createProjectService(host, { useInferredProjectPerProjectRoot: true });
|
||||
service.openClientFile(untitledFile, "const x = 10;", ts.ScriptKind.TS, "/user/username/projects/myproject");
|
||||
checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
checkProjectActualFiles(service.inferredProjects[0], [untitledFile, libFile.path]);
|
||||
const program = service.inferredProjects[0].getCurrentProgram()!;
|
||||
const sourceFile = program.getSourceFile(untitledFile)!;
|
||||
|
||||
@@ -132,9 +133,9 @@ describe("unittests:: tsserver:: dynamicFiles:: Untitled files", () => {
|
||||
service.closeClientFile(untitledFile);
|
||||
|
||||
// Open untitled file with different mode
|
||||
service.openClientFile(untitledFile, "const x = 10;", ts.ScriptKind.TSX, ts.tscWatch.projectRoot);
|
||||
ts.projectSystem.checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
ts.projectSystem.checkProjectActualFiles(service.inferredProjects[0], [untitledFile, ts.projectSystem.libFile.path]);
|
||||
service.openClientFile(untitledFile, "const x = 10;", ts.ScriptKind.TSX, "/user/username/projects/myproject");
|
||||
checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
checkProjectActualFiles(service.inferredProjects[0], [untitledFile, libFile.path]);
|
||||
const newProgram = service.inferredProjects[0].getCurrentProgram()!;
|
||||
const newSourceFile = newProgram.getSourceFile(untitledFile)!;
|
||||
assert.notStrictEqual(newProgram, program);
|
||||
@@ -144,12 +145,12 @@ describe("unittests:: tsserver:: dynamicFiles:: Untitled files", () => {
|
||||
|
||||
describe("unittests:: tsserver:: dynamicFiles:: ", () => {
|
||||
it("dynamic file without external project", () => {
|
||||
const file: ts.projectSystem.File = {
|
||||
const file: File = {
|
||||
path: "^walkThroughSnippet:/Users/UserName/projects/someProject/out/someFile#1.js",
|
||||
content: "var x = 10;"
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([ts.projectSystem.libFile], { useCaseSensitiveFileNames: true });
|
||||
const projectService = ts.projectSystem.createProjectService(host);
|
||||
const host = createServerHost([libFile], { useCaseSensitiveFileNames: true });
|
||||
const projectService = createProjectService(host);
|
||||
projectService.setCompilerOptionsForInferredProjects({
|
||||
module: ts.ModuleKind.CommonJS,
|
||||
allowJs: true,
|
||||
@@ -160,8 +161,8 @@ describe("unittests:: tsserver:: dynamicFiles:: ", () => {
|
||||
|
||||
projectService.checkNumberOfProjects({ inferredProjects: 1 });
|
||||
const project = projectService.inferredProjects[0];
|
||||
ts.projectSystem.checkProjectRootFiles(project, [file.path]);
|
||||
ts.projectSystem.checkProjectActualFiles(project, [file.path, ts.projectSystem.libFile.path]);
|
||||
checkProjectRootFiles(project, [file.path]);
|
||||
checkProjectActualFiles(project, [file.path, libFile.path]);
|
||||
verifyDynamic(projectService, `/${file.path}`);
|
||||
|
||||
assert.strictEqual(projectService.ensureDefaultProjectForFile(ts.server.toNormalizedPath(file.path)), project);
|
||||
@@ -188,30 +189,30 @@ describe("unittests:: tsserver:: dynamicFiles:: ", () => {
|
||||
});
|
||||
|
||||
describe("dynamic file with projectRootPath", () => {
|
||||
const file: ts.projectSystem.File = {
|
||||
const file: File = {
|
||||
path: "^walkThroughSnippet:/Users/UserName/projects/someProject/out/someFile#1.js",
|
||||
content: "var x = 10;"
|
||||
};
|
||||
const configFile: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const configFile: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: "{}"
|
||||
};
|
||||
const configProjectFile: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/a.ts`,
|
||||
const configProjectFile: File = {
|
||||
path: `/user/username/projects/myproject/a.ts`,
|
||||
content: "let y = 10;"
|
||||
};
|
||||
it("with useInferredProjectPerProjectRoot", () => {
|
||||
const host = ts.projectSystem.createServerHost([ts.projectSystem.libFile, configFile, configProjectFile], { useCaseSensitiveFileNames: true });
|
||||
const session = ts.projectSystem.createSession(host, { useInferredProjectPerProjectRoot: true });
|
||||
ts.projectSystem.openFilesForSession([{ file: file.path, projectRootPath: ts.tscWatch.projectRoot }], session);
|
||||
const host = createServerHost([libFile, configFile, configProjectFile], { useCaseSensitiveFileNames: true });
|
||||
const session = createSession(host, { useInferredProjectPerProjectRoot: true });
|
||||
openFilesForSession([{ file: file.path, projectRootPath: "/user/username/projects/myproject" }], session);
|
||||
|
||||
const projectService = session.getProjectService();
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 1 });
|
||||
ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[0], [file.path, ts.projectSystem.libFile.path]);
|
||||
verifyDynamic(projectService, `${ts.tscWatch.projectRoot}/${file.path}`);
|
||||
checkNumberOfProjects(projectService, { inferredProjects: 1 });
|
||||
checkProjectActualFiles(projectService.inferredProjects[0], [file.path, libFile.path]);
|
||||
verifyDynamic(projectService, `/user/username/projects/myproject/${file.path}`);
|
||||
|
||||
session.executeCommandSeq<ts.projectSystem.protocol.OutliningSpansRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.GetOutliningSpans,
|
||||
session.executeCommandSeq<ts.server.protocol.OutliningSpansRequest>({
|
||||
command: ts.server.protocol.CommandTypes.GetOutliningSpans,
|
||||
arguments: {
|
||||
file: file.path
|
||||
}
|
||||
@@ -220,16 +221,16 @@ describe("unittests:: tsserver:: dynamicFiles:: ", () => {
|
||||
// Without project root
|
||||
const file2Path = file.path.replace("#1", "#2");
|
||||
projectService.openClientFile(file2Path, file.content);
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 2 });
|
||||
ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[0], [file.path, ts.projectSystem.libFile.path]);
|
||||
ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[1], [file2Path, ts.projectSystem.libFile.path]);
|
||||
checkNumberOfProjects(projectService, { inferredProjects: 2 });
|
||||
checkProjectActualFiles(projectService.inferredProjects[0], [file.path, libFile.path]);
|
||||
checkProjectActualFiles(projectService.inferredProjects[1], [file2Path, libFile.path]);
|
||||
});
|
||||
|
||||
it("fails when useInferredProjectPerProjectRoot is false", () => {
|
||||
const host = ts.projectSystem.createServerHost([ts.projectSystem.libFile, configFile, configProjectFile], { useCaseSensitiveFileNames: true });
|
||||
const projectService = ts.projectSystem.createProjectService(host);
|
||||
const host = createServerHost([libFile, configFile, configProjectFile], { useCaseSensitiveFileNames: true });
|
||||
const projectService = createProjectService(host);
|
||||
try {
|
||||
projectService.openClientFile(file.path, file.content, /*scriptKind*/ undefined, ts.tscWatch.projectRoot);
|
||||
projectService.openClientFile(file.path, file.content, /*scriptKind*/ undefined, "/user/username/projects/myproject");
|
||||
}
|
||||
catch (e) {
|
||||
assert.strictEqual(
|
||||
@@ -240,7 +241,7 @@ describe("unittests:: tsserver:: dynamicFiles:: ", () => {
|
||||
const file2Path = file.path.replace("#1", "#2");
|
||||
projectService.openClientFile(file2Path, file.content);
|
||||
projectService.checkNumberOfProjects({ inferredProjects: 1 });
|
||||
ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[0], [file2Path, ts.projectSystem.libFile.path]);
|
||||
checkProjectActualFiles(projectService.inferredProjects[0], [file2Path, libFile.path]);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import * as ts from "../../../_namespaces/ts";
|
||||
import { createServerHost, File, libFile } from "../../virtualFileSystemWithWatch";
|
||||
import { createSessionWithEventTracking, checkProjectActualFiles, openFilesForSession, checkNumberOfProjects } from "../helpers";
|
||||
|
||||
describe("unittests:: tsserver:: events:: LargeFileReferencedEvent with large file", () => {
|
||||
|
||||
@@ -6,20 +8,20 @@ describe("unittests:: tsserver:: events:: LargeFileReferencedEvent with large fi
|
||||
return `src/large.${useLargeTsFile ? "ts" : "js"}`;
|
||||
}
|
||||
|
||||
function createSessionWithEventHandler(files: ts.projectSystem.File[], useLargeTsFile: boolean) {
|
||||
const largeFile: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/${getLargeFile(useLargeTsFile)}`,
|
||||
function createSessionWithEventHandler(files: File[], useLargeTsFile: boolean) {
|
||||
const largeFile: File = {
|
||||
path: `/user/username/projects/myproject/${getLargeFile(useLargeTsFile)}`,
|
||||
content: "export var x = 10;",
|
||||
fileSize: ts.server.maxFileSize + 1
|
||||
};
|
||||
files.push(largeFile);
|
||||
const host = ts.projectSystem.createServerHost(files);
|
||||
const { session, events: largeFileReferencedEvents } = ts.projectSystem.createSessionWithEventTracking<ts.server.LargeFileReferencedEvent>(host, ts.server.LargeFileReferencedEvent);
|
||||
const host = createServerHost(files);
|
||||
const { session, events: largeFileReferencedEvents } = createSessionWithEventTracking<ts.server.LargeFileReferencedEvent>(host, ts.server.LargeFileReferencedEvent);
|
||||
|
||||
return { session, verifyLargeFile };
|
||||
|
||||
function verifyLargeFile(project: ts.server.Project) {
|
||||
ts.projectSystem.checkProjectActualFiles(project, files.map(f => f.path));
|
||||
checkProjectActualFiles(project, files.map(f => f.path));
|
||||
|
||||
// large file for non ts file should be empty and for ts file should have content
|
||||
const service = session.getProjectService();
|
||||
@@ -35,32 +37,32 @@ describe("unittests:: tsserver:: events:: LargeFileReferencedEvent with large fi
|
||||
|
||||
function verifyLargeFile(useLargeTsFile: boolean) {
|
||||
it("when large file is included by tsconfig", () => {
|
||||
const file: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/src/file.ts`,
|
||||
const file: File = {
|
||||
path: `/user/username/projects/myproject/src/file.ts`,
|
||||
content: "export var y = 10;"
|
||||
};
|
||||
const tsconfig: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const tsconfig: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: JSON.stringify({ files: ["src/file.ts", getLargeFile(useLargeTsFile)], compilerOptions: { target: 1, allowJs: true } })
|
||||
};
|
||||
const files = [file, ts.projectSystem.libFile, tsconfig];
|
||||
const files = [file, libFile, tsconfig];
|
||||
const { session, verifyLargeFile } = createSessionWithEventHandler(files, useLargeTsFile);
|
||||
const service = session.getProjectService();
|
||||
ts.projectSystem.openFilesForSession([file], session);
|
||||
ts.projectSystem.checkNumberOfProjects(service, { configuredProjects: 1 });
|
||||
openFilesForSession([file], session);
|
||||
checkNumberOfProjects(service, { configuredProjects: 1 });
|
||||
verifyLargeFile(service.configuredProjects.get(tsconfig.path)!);
|
||||
});
|
||||
|
||||
it("when large file is included by module resolution", () => {
|
||||
const file: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/src/file.ts`,
|
||||
const file: File = {
|
||||
path: `/user/username/projects/myproject/src/file.ts`,
|
||||
content: `export var y = 10;import {x} from "./large"`
|
||||
};
|
||||
const files = [file, ts.projectSystem.libFile];
|
||||
const files = [file, libFile];
|
||||
const { session, verifyLargeFile } = createSessionWithEventHandler(files, useLargeTsFile);
|
||||
const service = session.getProjectService();
|
||||
ts.projectSystem.openFilesForSession([file], session);
|
||||
ts.projectSystem.checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
openFilesForSession([file], session);
|
||||
checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
verifyLargeFile(service.inferredProjects[0]);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import * as ts from "../../../_namespaces/ts";
|
||||
import { createServerHost, File, libFile } from "../../virtualFileSystemWithWatch";
|
||||
import { createSessionWithEventTracking, checkNumberOfProjects, configuredProjectAt, createProjectService, createLoggerWithInMemoryLogs, baselineTsserverLogs } from "../helpers";
|
||||
|
||||
describe("unittests:: tsserver:: events:: ProjectLanguageServiceStateEvent", () => {
|
||||
it("language service disabled events are triggered", () => {
|
||||
@@ -18,21 +20,21 @@ describe("unittests:: tsserver:: events:: ProjectLanguageServiceStateEvent", ()
|
||||
path: config.path,
|
||||
content: JSON.stringify({ exclude: ["largefile.js"] })
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([f1, f2, config]);
|
||||
const host = createServerHost([f1, f2, config]);
|
||||
const originalGetFileSize = host.getFileSize;
|
||||
host.getFileSize = (filePath: string) =>
|
||||
filePath === f2.path ? ts.server.maxProgramSizeForNonTsFiles + 1 : originalGetFileSize.call(host, filePath);
|
||||
|
||||
const { session, events } = ts.projectSystem.createSessionWithEventTracking<ts.server.ProjectLanguageServiceStateEvent>(host, ts.server.ProjectLanguageServiceStateEvent);
|
||||
const { session, events } = createSessionWithEventTracking<ts.server.ProjectLanguageServiceStateEvent>(host, ts.server.ProjectLanguageServiceStateEvent);
|
||||
session.executeCommand({
|
||||
seq: 0,
|
||||
type: "request",
|
||||
command: "open",
|
||||
arguments: { file: f1.path }
|
||||
} as ts.projectSystem.protocol.OpenRequest);
|
||||
} as ts.server.protocol.OpenRequest);
|
||||
const projectService = session.getProjectService();
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
const project = ts.projectSystem.configuredProjectAt(projectService, 0);
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
const project = configuredProjectAt(projectService, 0);
|
||||
assert.isFalse(project.languageServiceEnabled, "Language service enabled");
|
||||
assert.equal(events.length, 1, "should receive event");
|
||||
assert.equal(events[0].data.project, project, "project name");
|
||||
@@ -41,7 +43,7 @@ describe("unittests:: tsserver:: events:: ProjectLanguageServiceStateEvent", ()
|
||||
|
||||
host.writeFile(configWithExclude.path, configWithExclude.content);
|
||||
host.checkTimeoutQueueLengthAndRun(2);
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
assert.isTrue(project.languageServiceEnabled, "Language service enabled");
|
||||
assert.equal(events.length, 2, "should receive event");
|
||||
assert.equal(events[1].data.project, project, "project");
|
||||
@@ -50,16 +52,16 @@ describe("unittests:: tsserver:: events:: ProjectLanguageServiceStateEvent", ()
|
||||
});
|
||||
|
||||
it("Large file size is determined correctly", () => {
|
||||
const f1: ts.projectSystem.File = {
|
||||
const f1: File = {
|
||||
path: "/a/app.js",
|
||||
content: "let x = 1;"
|
||||
};
|
||||
const f2: ts.projectSystem.File = {
|
||||
const f2: File = {
|
||||
path: "/a/largefile.js",
|
||||
content: "",
|
||||
fileSize: ts.server.maxProgramSizeForNonTsFiles + 1
|
||||
};
|
||||
const f3: ts.projectSystem.File = {
|
||||
const f3: File = {
|
||||
path: "/a/extremlylarge.d.ts",
|
||||
content: "",
|
||||
fileSize: ts.server.maxProgramSizeForNonTsFiles + 100
|
||||
@@ -68,12 +70,12 @@ describe("unittests:: tsserver:: events:: ProjectLanguageServiceStateEvent", ()
|
||||
path: "/a/jsconfig.json",
|
||||
content: "{}"
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([f1, f2, f3, ts.projectSystem.libFile, config]);
|
||||
const service = ts.projectSystem.createProjectService(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) });
|
||||
const host = createServerHost([f1, f2, f3, libFile, config]);
|
||||
const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) });
|
||||
service.openClientFile(f1.path);
|
||||
const project = service.configuredProjects.get(config.path)!;
|
||||
service.logger.info(`languageServiceEnabled: ${project.languageServiceEnabled}`);
|
||||
service.logger.info(`lastFileExceededProgramSize: ${project.lastFileExceededProgramSize}`);
|
||||
ts.projectSystem.baselineTsserverLogs("projectLanguageServiceStateEvent", "large file size is determined correctly", service);
|
||||
baselineTsserverLogs("projectLanguageServiceStateEvent", "large file size is determined correctly", service);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,26 +1,28 @@
|
||||
import * as ts from "../../../_namespaces/ts";
|
||||
import { createServerHost, File, libFile, TestServerHost } from "../../virtualFileSystemWithWatch";
|
||||
import { TestSession, openFilesForSession, checkNumberOfProjects, protocolLocationFromSubstring, toExternalFiles, createSessionWithEventTracking, createSessionWithDefaultEventHandler } from "../helpers";
|
||||
|
||||
describe("unittests:: tsserver:: events:: ProjectLoadingStart and ProjectLoadingFinish events", () => {
|
||||
const aTs: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projects}/a/a.ts`,
|
||||
const aTs: File = {
|
||||
path: `/user/username/projects/a/a.ts`,
|
||||
content: "export class A { }"
|
||||
};
|
||||
const configA: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projects}/a/tsconfig.json`,
|
||||
const configA: File = {
|
||||
path: `/user/username/projects/a/tsconfig.json`,
|
||||
content: "{}"
|
||||
};
|
||||
const bTsPath = `${ts.tscWatch.projects}/b/b.ts`;
|
||||
const configBPath = `${ts.tscWatch.projects}/b/tsconfig.json`;
|
||||
const files = [ts.projectSystem.libFile, aTs, configA];
|
||||
const bTsPath = `/user/username/projects/b/b.ts`;
|
||||
const configBPath = `/user/username/projects/b/tsconfig.json`;
|
||||
const files = [libFile, aTs, configA];
|
||||
|
||||
function verifyProjectLoadingStartAndFinish(createSession: (host: ts.projectSystem.TestServerHost) => {
|
||||
session: ts.projectSystem.TestSession;
|
||||
function verifyProjectLoadingStartAndFinish(createSession: (host: TestServerHost) => {
|
||||
session: TestSession;
|
||||
getNumberOfEvents: () => number;
|
||||
clearEvents: () => void;
|
||||
verifyProjectLoadEvents: (expected: [ts.server.ProjectLoadingStartEvent, ts.server.ProjectLoadingFinishEvent]) => void;
|
||||
}) {
|
||||
function createSessionToVerifyEvent(files: readonly ts.projectSystem.File[]) {
|
||||
const host = ts.projectSystem.createServerHost(files);
|
||||
function createSessionToVerifyEvent(files: readonly File[]) {
|
||||
const host = createServerHost(files);
|
||||
const originalReadFile = host.readFile;
|
||||
const { session, getNumberOfEvents, clearEvents, verifyProjectLoadEvents } = createSession(host);
|
||||
host.readFile = file => {
|
||||
@@ -40,9 +42,9 @@ describe("unittests:: tsserver:: events:: ProjectLoadingStart and ProjectLoading
|
||||
clearEvents();
|
||||
}
|
||||
|
||||
function verifyEventWithOpenTs(file: ts.projectSystem.File, configPath: string, configuredProjects: number) {
|
||||
ts.projectSystem.openFilesForSession([file], session);
|
||||
ts.projectSystem.checkNumberOfProjects(service, { configuredProjects });
|
||||
function verifyEventWithOpenTs(file: File, configPath: string, configuredProjects: number) {
|
||||
openFilesForSession([file], session);
|
||||
checkNumberOfProjects(service, { configuredProjects });
|
||||
const project = service.configuredProjects.get(configPath)!;
|
||||
assert.isDefined(project);
|
||||
verifyEvent(project, `Creating possible configured project for ${file.path} to open`);
|
||||
@@ -50,11 +52,11 @@ describe("unittests:: tsserver:: events:: ProjectLoadingStart and ProjectLoading
|
||||
}
|
||||
|
||||
it("when project is created by open file", () => {
|
||||
const bTs: ts.projectSystem.File = {
|
||||
const bTs: File = {
|
||||
path: bTsPath,
|
||||
content: "export class B {}"
|
||||
};
|
||||
const configB: ts.projectSystem.File = {
|
||||
const configB: File = {
|
||||
path: configBPath,
|
||||
content: "{}"
|
||||
};
|
||||
@@ -74,11 +76,11 @@ describe("unittests:: tsserver:: events:: ProjectLoadingStart and ProjectLoading
|
||||
});
|
||||
|
||||
it("when change is detected in an extended config file", () => {
|
||||
const bTs: ts.projectSystem.File = {
|
||||
const bTs: File = {
|
||||
path: bTsPath,
|
||||
content: "export class B {}"
|
||||
};
|
||||
const configB: ts.projectSystem.File = {
|
||||
const configB: File = {
|
||||
path: configBPath,
|
||||
content: JSON.stringify({
|
||||
extends: "../a/tsconfig.json",
|
||||
@@ -103,22 +105,22 @@ describe("unittests:: tsserver:: events:: ProjectLoadingStart and ProjectLoading
|
||||
});
|
||||
|
||||
function verify(disableSourceOfProjectReferenceRedirect?: true) {
|
||||
const aDTs: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projects}/a/a.d.ts`,
|
||||
const aDTs: File = {
|
||||
path: `/user/username/projects/a/a.d.ts`,
|
||||
content: `export declare class A {
|
||||
}
|
||||
//# sourceMappingURL=a.d.ts.map
|
||||
`
|
||||
};
|
||||
const aDTsMap: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projects}/a/a.d.ts.map`,
|
||||
const aDTsMap: File = {
|
||||
path: `/user/username/projects/a/a.d.ts.map`,
|
||||
content: `{"version":3,"file":"a.d.ts","sourceRoot":"","sources":["./a.ts"],"names":[],"mappings":"AAAA,qBAAa,CAAC;CAAI"}`
|
||||
};
|
||||
const bTs: ts.projectSystem.File = {
|
||||
const bTs: File = {
|
||||
path: bTsPath,
|
||||
content: `import {A} from "../a/a"; new A();`
|
||||
};
|
||||
const configB: ts.projectSystem.File = {
|
||||
const configB: File = {
|
||||
path: configBPath,
|
||||
content: JSON.stringify({
|
||||
...(disableSourceOfProjectReferenceRedirect && {
|
||||
@@ -133,15 +135,15 @@ describe("unittests:: tsserver:: events:: ProjectLoadingStart and ProjectLoading
|
||||
const { service, session, verifyEventWithOpenTs, verifyEvent } = createSessionToVerifyEvent(files.concat(aDTs, aDTsMap, bTs, configB));
|
||||
verifyEventWithOpenTs(bTs, configB.path, 1);
|
||||
|
||||
session.executeCommandSeq<ts.projectSystem.protocol.ReferencesRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.References,
|
||||
session.executeCommandSeq<ts.server.protocol.ReferencesRequest>({
|
||||
command: ts.server.protocol.CommandTypes.References,
|
||||
arguments: {
|
||||
file: bTs.path,
|
||||
...ts.projectSystem.protocolLocationFromSubstring(bTs.content, "A()")
|
||||
...protocolLocationFromSubstring(bTs.content, "A()")
|
||||
}
|
||||
});
|
||||
|
||||
ts.projectSystem.checkNumberOfProjects(service, { configuredProjects: 2 });
|
||||
checkNumberOfProjects(service, { configuredProjects: 2 });
|
||||
const project = service.configuredProjects.get(configA.path)!;
|
||||
assert.isDefined(project);
|
||||
verifyEvent(
|
||||
@@ -154,17 +156,17 @@ describe("unittests:: tsserver:: events:: ProjectLoadingStart and ProjectLoading
|
||||
});
|
||||
|
||||
describe("with external projects and config files ", () => {
|
||||
const projectFileName = `${ts.tscWatch.projects}/a/project.csproj`;
|
||||
const projectFileName = `/user/username/projects/a/project.csproj`;
|
||||
|
||||
function createSession(lazyConfiguredProjectsFromExternalProject: boolean) {
|
||||
const { session, service, verifyEvent: verifyEventWorker, getNumberOfEvents } = createSessionToVerifyEvent(files);
|
||||
service.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject } });
|
||||
service.openExternalProject({
|
||||
projectFileName,
|
||||
rootFiles: ts.projectSystem.toExternalFiles([aTs.path, configA.path]),
|
||||
rootFiles: toExternalFiles([aTs.path, configA.path]),
|
||||
options: {}
|
||||
} as ts.projectSystem.protocol.ExternalProject);
|
||||
ts.projectSystem.checkNumberOfProjects(service, { configuredProjects: 1 });
|
||||
} as ts.server.protocol.ExternalProject);
|
||||
checkNumberOfProjects(service, { configuredProjects: 1 });
|
||||
return { session, service, verifyEvent, getNumberOfEvents };
|
||||
|
||||
function verifyEvent() {
|
||||
@@ -183,7 +185,7 @@ describe("unittests:: tsserver:: events:: ProjectLoadingStart and ProjectLoading
|
||||
const { verifyEvent, getNumberOfEvents, session } = createSession(/*lazyConfiguredProjectsFromExternalProject*/ true);
|
||||
assert.equal(getNumberOfEvents(), 0);
|
||||
|
||||
ts.projectSystem.openFilesForSession([aTs], session);
|
||||
openFilesForSession([aTs], session);
|
||||
verifyEvent();
|
||||
});
|
||||
|
||||
@@ -199,7 +201,7 @@ describe("unittests:: tsserver:: events:: ProjectLoadingStart and ProjectLoading
|
||||
|
||||
describe("when using event handler", () => {
|
||||
verifyProjectLoadingStartAndFinish(host => {
|
||||
const { session, events } = ts.projectSystem.createSessionWithEventTracking<ts.server.ProjectLoadingStartEvent | ts.server.ProjectLoadingFinishEvent>(host, [ts.server.ProjectLoadingStartEvent, ts.server.ProjectLoadingFinishEvent]);
|
||||
const { session, events } = createSessionWithEventTracking<ts.server.ProjectLoadingStartEvent | ts.server.ProjectLoadingFinishEvent>(host, [ts.server.ProjectLoadingStartEvent, ts.server.ProjectLoadingFinishEvent]);
|
||||
return {
|
||||
session,
|
||||
getNumberOfEvents: () => events.length,
|
||||
@@ -211,7 +213,7 @@ describe("unittests:: tsserver:: events:: ProjectLoadingStart and ProjectLoading
|
||||
|
||||
describe("when using default event handler", () => {
|
||||
verifyProjectLoadingStartAndFinish(host => {
|
||||
const { session, getEvents, clearEvents } = ts.projectSystem.createSessionWithDefaultEventHandler<ts.projectSystem.protocol.ProjectLoadingStartEvent | ts.projectSystem.protocol.ProjectLoadingFinishEvent>(host, [ts.server.ProjectLoadingStartEvent, ts.server.ProjectLoadingFinishEvent]);
|
||||
const { session, getEvents, clearEvents } = createSessionWithDefaultEventHandler<ts.server.protocol.ProjectLoadingStartEvent | ts.server.protocol.ProjectLoadingFinishEvent>(host, [ts.server.ProjectLoadingStartEvent, ts.server.ProjectLoadingFinishEvent]);
|
||||
return {
|
||||
session,
|
||||
getNumberOfEvents: () => getEvents().length,
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import * as ts from "../../../_namespaces/ts";
|
||||
import { createServerHost, File, libFile, TestServerHost } from "../../virtualFileSystemWithWatch";
|
||||
import { TestSession, Logger, createLoggerWithInMemoryLogs, baselineTsserverLogs, createSessionWithEventTracking, createSessionWithDefaultEventHandler, createHasErrorMessageLogger } from "../helpers";
|
||||
|
||||
describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => {
|
||||
function verifyFiles(caption: string, actual: readonly string[], expected: readonly string[]) {
|
||||
@@ -11,44 +13,44 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => {
|
||||
});
|
||||
}
|
||||
|
||||
function createVerifyInitialOpen(session: ts.projectSystem.TestSession, verifyProjectsUpdatedInBackgroundEventHandler: (events: ts.server.ProjectsUpdatedInBackgroundEvent[]) => void) {
|
||||
return (file: ts.projectSystem.File) => {
|
||||
function createVerifyInitialOpen(session: TestSession, verifyProjectsUpdatedInBackgroundEventHandler: (events: ts.server.ProjectsUpdatedInBackgroundEvent[]) => void) {
|
||||
return (file: File) => {
|
||||
session.executeCommandSeq({
|
||||
command: ts.server.CommandNames.Open,
|
||||
arguments: {
|
||||
file: file.path
|
||||
}
|
||||
} as ts.projectSystem.protocol.OpenRequest);
|
||||
} as ts.server.protocol.OpenRequest);
|
||||
verifyProjectsUpdatedInBackgroundEventHandler([]);
|
||||
};
|
||||
}
|
||||
|
||||
interface ProjectsUpdatedInBackgroundEventVerifier {
|
||||
session: ts.projectSystem.TestSession;
|
||||
session: TestSession;
|
||||
verifyProjectsUpdatedInBackgroundEventHandler(events: ts.server.ProjectsUpdatedInBackgroundEvent[]): void;
|
||||
verifyInitialOpen(file: ts.projectSystem.File): void;
|
||||
verifyInitialOpen(file: File): void;
|
||||
}
|
||||
|
||||
function verifyProjectsUpdatedInBackgroundEvent(scenario: string, createSession: (host: ts.projectSystem.TestServerHost, logger?: ts.projectSystem.Logger) => ProjectsUpdatedInBackgroundEventVerifier) {
|
||||
function verifyProjectsUpdatedInBackgroundEvent(scenario: string, createSession: (host: TestServerHost, logger?: Logger) => ProjectsUpdatedInBackgroundEventVerifier) {
|
||||
it("when adding new file", () => {
|
||||
const commonFile1: ts.projectSystem.File = {
|
||||
const commonFile1: File = {
|
||||
path: "/a/b/file1.ts",
|
||||
content: "export var x = 10;"
|
||||
};
|
||||
const commonFile2: ts.projectSystem.File = {
|
||||
const commonFile2: File = {
|
||||
path: "/a/b/file2.ts",
|
||||
content: "export var y = 10;"
|
||||
};
|
||||
const commonFile3: ts.projectSystem.File = {
|
||||
const commonFile3: File = {
|
||||
path: "/a/b/file3.ts",
|
||||
content: "export var z = 10;"
|
||||
};
|
||||
const configFile: ts.projectSystem.File = {
|
||||
const configFile: File = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: `{}`
|
||||
};
|
||||
const openFiles = [commonFile1.path];
|
||||
const host = ts.projectSystem.createServerHost([commonFile1, ts.projectSystem.libFile, configFile]);
|
||||
const host = createServerHost([commonFile1, libFile, configFile]);
|
||||
const { verifyProjectsUpdatedInBackgroundEventHandler, verifyInitialOpen } = createSession(host);
|
||||
verifyInitialOpen(commonFile1);
|
||||
|
||||
@@ -73,25 +75,25 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => {
|
||||
|
||||
describe("with --out or --outFile setting", () => {
|
||||
function verifyEventWithOutSettings(compilerOptions: ts.CompilerOptions = {}) {
|
||||
const config: ts.projectSystem.File = {
|
||||
const config: File = {
|
||||
path: "/a/tsconfig.json",
|
||||
content: JSON.stringify({
|
||||
compilerOptions
|
||||
})
|
||||
};
|
||||
|
||||
const f1: ts.projectSystem.File = {
|
||||
const f1: File = {
|
||||
path: "/a/a.ts",
|
||||
content: "export let x = 1"
|
||||
};
|
||||
const f2: ts.projectSystem.File = {
|
||||
const f2: File = {
|
||||
path: "/a/b.ts",
|
||||
content: "export let y = 1"
|
||||
};
|
||||
|
||||
const openFiles = [f1.path];
|
||||
const files = [f1, config, ts.projectSystem.libFile];
|
||||
const host = ts.projectSystem.createServerHost(files);
|
||||
const files = [f1, config, libFile];
|
||||
const host = createServerHost(files);
|
||||
const { verifyInitialOpen, verifyProjectsUpdatedInBackgroundEventHandler } = createSession(host);
|
||||
verifyInitialOpen(f1);
|
||||
|
||||
@@ -138,32 +140,32 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => {
|
||||
/** custom config file options */
|
||||
configObj?: any;
|
||||
/** Additional files and folders to add */
|
||||
getAdditionalFileOrFolder?(): ts.projectSystem.File[];
|
||||
getAdditionalFileOrFolder?(): File[];
|
||||
/** initial list of files to reload in fs and first file in this list being the file to open */
|
||||
firstReloadFileList?: string[];
|
||||
}
|
||||
function getInitialState({ configObj = {}, getAdditionalFileOrFolder, firstReloadFileList }: InitialStateParams = {}) {
|
||||
const moduleFile1: ts.projectSystem.File = {
|
||||
const moduleFile1: File = {
|
||||
path: moduleFile1Path,
|
||||
content: "export function Foo() { };",
|
||||
};
|
||||
|
||||
const file1Consumer1: ts.projectSystem.File = {
|
||||
const file1Consumer1: File = {
|
||||
path: file1Consumer1Path,
|
||||
content: `import {Foo} from "./moduleFile1"; export var y = 10;`,
|
||||
};
|
||||
|
||||
const file1Consumer2: ts.projectSystem.File = {
|
||||
const file1Consumer2: File = {
|
||||
path: "/a/b/file1Consumer2.ts",
|
||||
content: `import {Foo} from "./moduleFile1"; let z = 10;`,
|
||||
};
|
||||
|
||||
const moduleFile2: ts.projectSystem.File = {
|
||||
const moduleFile2: File = {
|
||||
path: "/a/b/moduleFile2.ts",
|
||||
content: `export var Foo4 = 10;`,
|
||||
};
|
||||
|
||||
const globalFile3: ts.projectSystem.File = {
|
||||
const globalFile3: File = {
|
||||
path: "/a/b/globalFile3.ts",
|
||||
content: `interface GlobalFoo { age: number }`
|
||||
};
|
||||
@@ -174,10 +176,10 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => {
|
||||
content: JSON.stringify(configObj || { compilerOptions: {} })
|
||||
};
|
||||
|
||||
const files: ts.projectSystem.File[] = [file1Consumer1, moduleFile1, file1Consumer2, moduleFile2, ...additionalFiles, globalFile3, ts.projectSystem.libFile, configFile];
|
||||
const files: File[] = [file1Consumer1, moduleFile1, file1Consumer2, moduleFile2, ...additionalFiles, globalFile3, libFile, configFile];
|
||||
|
||||
const filesToReload = firstReloadFileList && getFiles(firstReloadFileList) || files;
|
||||
const host = ts.projectSystem.createServerHost([filesToReload[0], configFile]);
|
||||
const host = createServerHost([filesToReload[0], configFile]);
|
||||
|
||||
// Initial project creation
|
||||
const { session, verifyProjectsUpdatedInBackgroundEventHandler, verifyInitialOpen } = createSession(host);
|
||||
@@ -220,8 +222,8 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => {
|
||||
}]);
|
||||
}
|
||||
|
||||
function updateContentOfOpenFile(file: ts.projectSystem.File, newContent: string) {
|
||||
session.executeCommandSeq<ts.projectSystem.protocol.ChangeRequest>({
|
||||
function updateContentOfOpenFile(file: File, newContent: string) {
|
||||
session.executeCommandSeq<ts.server.protocol.ChangeRequest>({
|
||||
command: ts.server.CommandNames.Change,
|
||||
arguments: {
|
||||
file: file.path,
|
||||
@@ -335,7 +337,7 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => {
|
||||
});
|
||||
|
||||
it("should return cascaded affected file list", () => {
|
||||
const file1Consumer1Consumer1: ts.projectSystem.File = {
|
||||
const file1Consumer1Consumer1: File = {
|
||||
path: "/a/b/file1Consumer1Consumer1.ts",
|
||||
content: `import {y} from "./file1Consumer1";`
|
||||
};
|
||||
@@ -357,13 +359,13 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => {
|
||||
});
|
||||
|
||||
it("should work fine for files with circular references", () => {
|
||||
const file1: ts.projectSystem.File = {
|
||||
const file1: File = {
|
||||
path: "/a/b/file1.ts",
|
||||
content: `
|
||||
/// <reference path="./file2.ts" />
|
||||
export var t1 = 10;`
|
||||
};
|
||||
const file2: ts.projectSystem.File = {
|
||||
const file2: File = {
|
||||
path: "/a/b/file2.ts",
|
||||
content: `
|
||||
/// <reference path="./file1.ts" />
|
||||
@@ -371,7 +373,7 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => {
|
||||
};
|
||||
const { host, verifyProjectsUpdatedInBackgroundEvent } = getInitialState({
|
||||
getAdditionalFileOrFolder: () => [file1, file2],
|
||||
firstReloadFileList: [file1.path, ts.projectSystem.libFile.path, file2.path, configFilePath]
|
||||
firstReloadFileList: [file1.path, libFile.path, file2.path, configFilePath]
|
||||
});
|
||||
|
||||
host.writeFile(file2.path, file2.content + "export var t3 = 10;");
|
||||
@@ -379,7 +381,7 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => {
|
||||
});
|
||||
|
||||
it("should detect removed code file", () => {
|
||||
const referenceFile1: ts.projectSystem.File = {
|
||||
const referenceFile1: File = {
|
||||
path: "/a/b/referenceFile1.ts",
|
||||
content: `
|
||||
/// <reference path="./moduleFile1.ts" />
|
||||
@@ -387,7 +389,7 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => {
|
||||
};
|
||||
const { host, verifyProjectsUpdatedInBackgroundEvent } = getInitialState({
|
||||
getAdditionalFileOrFolder: () => [referenceFile1],
|
||||
firstReloadFileList: [referenceFile1.path, ts.projectSystem.libFile.path, moduleFile1Path, configFilePath]
|
||||
firstReloadFileList: [referenceFile1.path, libFile.path, moduleFile1Path, configFilePath]
|
||||
});
|
||||
|
||||
host.deleteFile(moduleFile1Path);
|
||||
@@ -395,7 +397,7 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => {
|
||||
});
|
||||
|
||||
it("should detect non-existing code file", () => {
|
||||
const referenceFile1: ts.projectSystem.File = {
|
||||
const referenceFile1: File = {
|
||||
path: "/a/b/referenceFile1.ts",
|
||||
content: `
|
||||
/// <reference path="./moduleFile2.ts" />
|
||||
@@ -403,7 +405,7 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => {
|
||||
};
|
||||
const { host, moduleFile2, updateContentOfOpenFile, verifyNoProjectsUpdatedInBackgroundEvent, verifyProjectsUpdatedInBackgroundEvent } = getInitialState({
|
||||
getAdditionalFileOrFolder: () => [referenceFile1],
|
||||
firstReloadFileList: [referenceFile1.path, ts.projectSystem.libFile.path, configFilePath]
|
||||
firstReloadFileList: [referenceFile1.path, libFile.path, configFilePath]
|
||||
});
|
||||
|
||||
updateContentOfOpenFile(referenceFile1, referenceFile1.content + "export var yy = Foo();");
|
||||
@@ -419,26 +421,26 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => {
|
||||
function verifyWithMaxCacheLimit(subScenario: string, useSlashRootAsSomeNotRootFolderInUserDirectory: boolean) {
|
||||
it(subScenario, () => {
|
||||
const rootFolder = useSlashRootAsSomeNotRootFolderInUserDirectory ? "/user/username/rootfolder/otherfolder/" : "/";
|
||||
const file1: ts.projectSystem.File = {
|
||||
const file1: File = {
|
||||
path: rootFolder + "a/b/project/file1.ts",
|
||||
content: 'import a from "file2"'
|
||||
};
|
||||
const file2: ts.projectSystem.File = {
|
||||
const file2: File = {
|
||||
path: rootFolder + "a/b/node_modules/file2.d.ts",
|
||||
content: "export class a { }"
|
||||
};
|
||||
const file3: ts.projectSystem.File = {
|
||||
const file3: File = {
|
||||
path: rootFolder + "a/b/project/file3.ts",
|
||||
content: "export class c { }"
|
||||
};
|
||||
const configFile: ts.projectSystem.File = {
|
||||
const configFile: File = {
|
||||
path: rootFolder + "a/b/project/tsconfig.json",
|
||||
content: JSON.stringify({ compilerOptions: { typeRoots: [] } })
|
||||
};
|
||||
|
||||
const openFiles = [file1.path];
|
||||
const host = ts.projectSystem.createServerHost([file1, file3, ts.projectSystem.libFile, configFile]);
|
||||
const { session, verifyInitialOpen, verifyProjectsUpdatedInBackgroundEventHandler } = createSession(host, ts.projectSystem.createLoggerWithInMemoryLogs(host));
|
||||
const host = createServerHost([file1, file3, libFile, configFile]);
|
||||
const { session, verifyInitialOpen, verifyProjectsUpdatedInBackgroundEventHandler } = createSession(host, createLoggerWithInMemoryLogs(host));
|
||||
verifyInitialOpen(file1);
|
||||
|
||||
file3.content += "export class d {}";
|
||||
@@ -463,7 +465,7 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => {
|
||||
openFiles
|
||||
}
|
||||
}] : []);
|
||||
ts.projectSystem.baselineTsserverLogs("projectUpdatedInBackground", `${scenario} and ${subScenario}`, session);
|
||||
baselineTsserverLogs("projectUpdatedInBackground", `${scenario} and ${subScenario}`, session);
|
||||
});
|
||||
}
|
||||
verifyWithMaxCacheLimit("project is not at root level", /*useSlashRootAsSomeNotRootFolderInUserDirectory*/ true);
|
||||
@@ -474,8 +476,8 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => {
|
||||
describe("when event handler is set in the session", () => {
|
||||
verifyProjectsUpdatedInBackgroundEvent("when event handler is set in the session", createSessionWithProjectChangedEventHandler);
|
||||
|
||||
function createSessionWithProjectChangedEventHandler(host: ts.projectSystem.TestServerHost, logger: ts.projectSystem.Logger | undefined): ProjectsUpdatedInBackgroundEventVerifier {
|
||||
const { session, events: projectChangedEvents } = ts.projectSystem.createSessionWithEventTracking<ts.server.ProjectsUpdatedInBackgroundEvent>(
|
||||
function createSessionWithProjectChangedEventHandler(host: TestServerHost, logger: Logger | undefined): ProjectsUpdatedInBackgroundEventVerifier {
|
||||
const { session, events: projectChangedEvents } = createSessionWithEventTracking<ts.server.ProjectsUpdatedInBackgroundEvent>(
|
||||
host,
|
||||
ts.server.ProjectsUpdatedInBackgroundEvent,
|
||||
logger && { logger }
|
||||
@@ -518,11 +520,11 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => {
|
||||
});
|
||||
|
||||
|
||||
function createSessionThatUsesEvents(host: ts.projectSystem.TestServerHost, logger: ts.projectSystem.Logger | undefined, noGetErrOnBackgroundUpdate?: boolean): ProjectsUpdatedInBackgroundEventVerifier {
|
||||
const { session, getEvents, clearEvents } = ts.projectSystem.createSessionWithDefaultEventHandler<ts.projectSystem.protocol.ProjectsUpdatedInBackgroundEvent>(
|
||||
function createSessionThatUsesEvents(host: TestServerHost, logger: Logger | undefined, noGetErrOnBackgroundUpdate?: boolean): ProjectsUpdatedInBackgroundEventVerifier {
|
||||
const { session, getEvents, clearEvents } = createSessionWithDefaultEventHandler<ts.server.protocol.ProjectsUpdatedInBackgroundEvent>(
|
||||
host,
|
||||
ts.server.ProjectsUpdatedInBackgroundEvent,
|
||||
{ noGetErrOnBackgroundUpdate, logger: logger || ts.projectSystem.createHasErrorMessageLogger() }
|
||||
{ noGetErrOnBackgroundUpdate, logger: logger || createHasErrorMessageLogger() }
|
||||
);
|
||||
|
||||
return {
|
||||
@@ -532,7 +534,7 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => {
|
||||
};
|
||||
|
||||
function verifyProjectsUpdatedInBackgroundEventHandler(expected: readonly ts.server.ProjectsUpdatedInBackgroundEvent[]) {
|
||||
const expectedEvents: ts.projectSystem.protocol.ProjectsUpdatedInBackgroundEventBody[] = ts.map(expected, e => {
|
||||
const expectedEvents: ts.server.protocol.ProjectsUpdatedInBackgroundEventBody[] = ts.map(expected, e => {
|
||||
return {
|
||||
openFiles: e.data.openFiles
|
||||
};
|
||||
|
||||
@@ -1,34 +1,36 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { createServerHost, File } from "../virtualFileSystemWithWatch";
|
||||
import { createSession, openFilesForSession, configuredProjectAt, executeSessionRequest } from "./helpers";
|
||||
|
||||
const packageJson: ts.projectSystem.File = {
|
||||
const packageJson: File = {
|
||||
path: "/package.json",
|
||||
content: `{ "dependencies": { "mobx": "*" } }`
|
||||
};
|
||||
const aTs: ts.projectSystem.File = {
|
||||
const aTs: File = {
|
||||
path: "/a.ts",
|
||||
content: "export const foo = 0;",
|
||||
};
|
||||
const bTs: ts.projectSystem.File = {
|
||||
const bTs: File = {
|
||||
path: "/b.ts",
|
||||
content: "foo",
|
||||
};
|
||||
const tsconfig: ts.projectSystem.File = {
|
||||
const tsconfig: File = {
|
||||
path: "/tsconfig.json",
|
||||
content: "{}",
|
||||
};
|
||||
const ambientDeclaration: ts.projectSystem.File = {
|
||||
const ambientDeclaration: File = {
|
||||
path: "/ambient.d.ts",
|
||||
content: "declare module 'ambient' {}"
|
||||
};
|
||||
const mobxPackageJson: ts.projectSystem.File = {
|
||||
const mobxPackageJson: File = {
|
||||
path: "/node_modules/mobx/package.json",
|
||||
content: `{ "name": "mobx", "version": "1.0.0" }`
|
||||
};
|
||||
const mobxDts: ts.projectSystem.File = {
|
||||
const mobxDts: File = {
|
||||
path: "/node_modules/mobx/index.d.ts",
|
||||
content: "export declare function observable(): unknown;"
|
||||
};
|
||||
const exportEqualsMappedType: ts.projectSystem.File = {
|
||||
const exportEqualsMappedType: File = {
|
||||
path: "/lib/foo/constants.d.ts",
|
||||
content: `
|
||||
type Signals = "SIGINT" | "SIGABRT";
|
||||
@@ -96,8 +98,8 @@ describe("unittests:: tsserver:: exportMapCache", () => {
|
||||
const symbolIdBefore = ts.getSymbolId(sigintPropBefore![0].symbol);
|
||||
|
||||
// Update program without clearing cache
|
||||
session.executeCommandSeq<ts.projectSystem.protocol.UpdateOpenRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.UpdateOpen,
|
||||
session.executeCommandSeq<ts.server.protocol.UpdateOpenRequest>({
|
||||
command: ts.server.protocol.CommandTypes.UpdateOpen,
|
||||
arguments: {
|
||||
changedFiles: [{
|
||||
fileName: bTs.path,
|
||||
@@ -123,22 +125,22 @@ describe("unittests:: tsserver:: exportMapCache", () => {
|
||||
});
|
||||
|
||||
function setup() {
|
||||
const host = ts.projectSystem.createServerHost([aTs, bTs, ambientDeclaration, tsconfig, packageJson, mobxPackageJson, mobxDts, exportEqualsMappedType]);
|
||||
const session = ts.projectSystem.createSession(host);
|
||||
ts.projectSystem.openFilesForSession([aTs, bTs], session);
|
||||
const host = createServerHost([aTs, bTs, ambientDeclaration, tsconfig, packageJson, mobxPackageJson, mobxDts, exportEqualsMappedType]);
|
||||
const session = createSession(host);
|
||||
openFilesForSession([aTs, bTs], session);
|
||||
const projectService = session.getProjectService();
|
||||
const project = ts.projectSystem.configuredProjectAt(projectService, 0);
|
||||
const project = configuredProjectAt(projectService, 0);
|
||||
triggerCompletions();
|
||||
const checker = project.getLanguageService().getProgram()!.getTypeChecker();
|
||||
return { host, project, projectService, session, exportMapCache: project.getCachedExportInfoMap(), checker, triggerCompletions };
|
||||
|
||||
function triggerCompletions() {
|
||||
const requestLocation: ts.projectSystem.protocol.FileLocationRequestArgs = {
|
||||
const requestLocation: ts.server.protocol.FileLocationRequestArgs = {
|
||||
file: bTs.path,
|
||||
line: 1,
|
||||
offset: 3,
|
||||
};
|
||||
ts.projectSystem.executeSessionRequest<ts.projectSystem.protocol.CompletionsRequest, ts.projectSystem.protocol.CompletionInfoResponse>(session, ts.projectSystem.protocol.CommandTypes.CompletionInfo, {
|
||||
executeSessionRequest<ts.server.protocol.CompletionsRequest, ts.server.protocol.CompletionInfoResponse>(session, ts.server.protocol.CommandTypes.CompletionInfo, {
|
||||
...requestLocation,
|
||||
includeExternalModuleExports: true,
|
||||
prefix: "foo",
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import * as Harness from "../../_namespaces/Harness";
|
||||
import { createServerHost, File, libFile } from "../virtualFileSystemWithWatch";
|
||||
import { createProjectService, toExternalFiles, checkProjectActualFiles, toExternalFile, createSession, checkNumberOfProjects, checkNumberOfExternalProjects, checkNumberOfInferredProjects, verifyDynamic, checkProjectRootFiles, configuredProjectAt } from "./helpers";
|
||||
|
||||
describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
describe("can handle tsconfig file name with difference casing", () => {
|
||||
@@ -15,32 +17,32 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
})
|
||||
};
|
||||
|
||||
const host = ts.projectSystem.createServerHost([f1, config], { useCaseSensitiveFileNames: false });
|
||||
const service = ts.projectSystem.createProjectService(host);
|
||||
const host = createServerHost([f1, config], { useCaseSensitiveFileNames: false });
|
||||
const service = createProjectService(host);
|
||||
service.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject } });
|
||||
const upperCaseConfigFilePath = ts.combinePaths(ts.getDirectoryPath(config.path).toUpperCase(), ts.getBaseFileName(config.path));
|
||||
service.openExternalProject({
|
||||
projectFileName: "/a/b/project.csproj",
|
||||
rootFiles: ts.projectSystem.toExternalFiles([f1.path, upperCaseConfigFilePath]),
|
||||
rootFiles: toExternalFiles([f1.path, upperCaseConfigFilePath]),
|
||||
options: {}
|
||||
} as ts.projectSystem.protocol.ExternalProject);
|
||||
} as ts.server.protocol.ExternalProject);
|
||||
service.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
const project = service.configuredProjects.get(config.path)!;
|
||||
if (lazyConfiguredProjectsFromExternalProject) {
|
||||
assert.equal(project.pendingReload, ts.ConfigFileProgramReloadLevel.Full); // External project referenced configured project pending to be reloaded
|
||||
ts.projectSystem.checkProjectActualFiles(project, ts.emptyArray);
|
||||
checkProjectActualFiles(project, ts.emptyArray);
|
||||
}
|
||||
else {
|
||||
assert.equal(project.pendingReload, ts.ConfigFileProgramReloadLevel.None); // External project referenced configured project loaded
|
||||
ts.projectSystem.checkProjectActualFiles(project, [upperCaseConfigFilePath]);
|
||||
checkProjectActualFiles(project, [upperCaseConfigFilePath]);
|
||||
}
|
||||
|
||||
service.openClientFile(f1.path);
|
||||
service.checkNumberOfProjects({ configuredProjects: 1, inferredProjects: 1 });
|
||||
|
||||
assert.equal(project.pendingReload, ts.ConfigFileProgramReloadLevel.None); // External project referenced configured project is updated
|
||||
ts.projectSystem.checkProjectActualFiles(project, [upperCaseConfigFilePath]);
|
||||
ts.projectSystem.checkProjectActualFiles(service.inferredProjects[0], [f1.path]);
|
||||
checkProjectActualFiles(project, [upperCaseConfigFilePath]);
|
||||
checkProjectActualFiles(service.inferredProjects[0], [f1.path]);
|
||||
}
|
||||
|
||||
it("when lazyConfiguredProjectsFromExternalProject not set", () => {
|
||||
@@ -57,9 +59,9 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
path: "/a/file1.ts",
|
||||
content: "let x = [1, 2];"
|
||||
};
|
||||
const p1 = { projectFileName: "/a/proj1.csproj", rootFiles: [ts.projectSystem.toExternalFile(f1.path)], options: {} };
|
||||
const p1 = { projectFileName: "/a/proj1.csproj", rootFiles: [toExternalFile(f1.path)], options: {} };
|
||||
|
||||
const host = ts.projectSystem.createServerHost([f1]);
|
||||
const host = createServerHost([f1]);
|
||||
host.require = (_initialPath, moduleName) => {
|
||||
assert.equal(moduleName, "myplugin");
|
||||
return {
|
||||
@@ -85,17 +87,17 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
error: undefined
|
||||
};
|
||||
};
|
||||
const session = ts.projectSystem.createSession(host, { globalPlugins: ["myplugin"] });
|
||||
const session = createSession(host, { globalPlugins: ["myplugin"] });
|
||||
|
||||
session.executeCommand({
|
||||
seq: 1,
|
||||
type: "request",
|
||||
command: "openExternalProjects",
|
||||
arguments: { projects: [p1] }
|
||||
} as ts.projectSystem.protocol.OpenExternalProjectsRequest);
|
||||
} as ts.server.protocol.OpenExternalProjectsRequest);
|
||||
|
||||
const projectService = session.getProjectService();
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { externalProjects: 1 });
|
||||
checkNumberOfProjects(projectService, { externalProjects: 1 });
|
||||
assert.equal(projectService.externalProjects[0].getProjectName(), p1.projectFileName);
|
||||
|
||||
const handlerResponse = session.executeCommand({
|
||||
@@ -106,10 +108,10 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
file: f1.path,
|
||||
projectFileName: p1.projectFileName
|
||||
}
|
||||
} as ts.projectSystem.protocol.SemanticDiagnosticsSyncRequest);
|
||||
} as ts.server.protocol.SemanticDiagnosticsSyncRequest);
|
||||
|
||||
assert.isDefined(handlerResponse.response);
|
||||
const response = handlerResponse.response as ts.projectSystem.protocol.Diagnostic[];
|
||||
const response = handlerResponse.response as ts.server.protocol.Diagnostic[];
|
||||
assert.equal(response.length, 1);
|
||||
assert.equal(response[0].text, "Plugin diagnostic");
|
||||
});
|
||||
@@ -127,23 +129,23 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
path: "/c/app.ts",
|
||||
content: "let x = 1"
|
||||
};
|
||||
const makeProject = (f: ts.projectSystem.File) => ({ projectFileName: f.path + ".csproj", rootFiles: [ts.projectSystem.toExternalFile(f.path)], options: {} });
|
||||
const makeProject = (f: File) => ({ projectFileName: f.path + ".csproj", rootFiles: [toExternalFile(f.path)], options: {} });
|
||||
const p1 = makeProject(f1);
|
||||
const p2 = makeProject(f2);
|
||||
const p3 = makeProject(f3);
|
||||
|
||||
const host = ts.projectSystem.createServerHost([f1, f2, f3]);
|
||||
const session = ts.projectSystem.createSession(host);
|
||||
const host = createServerHost([f1, f2, f3]);
|
||||
const session = createSession(host);
|
||||
|
||||
session.executeCommand({
|
||||
seq: 1,
|
||||
type: "request",
|
||||
command: "openExternalProjects",
|
||||
arguments: { projects: [p1, p2] }
|
||||
} as ts.projectSystem.protocol.OpenExternalProjectsRequest);
|
||||
} as ts.server.protocol.OpenExternalProjectsRequest);
|
||||
|
||||
const projectService = session.getProjectService();
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { externalProjects: 2 });
|
||||
checkNumberOfProjects(projectService, { externalProjects: 2 });
|
||||
assert.equal(projectService.externalProjects[0].getProjectName(), p1.projectFileName);
|
||||
assert.equal(projectService.externalProjects[1].getProjectName(), p2.projectFileName);
|
||||
|
||||
@@ -152,8 +154,8 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
type: "request",
|
||||
command: "openExternalProjects",
|
||||
arguments: { projects: [p1, p3] }
|
||||
} as ts.projectSystem.protocol.OpenExternalProjectsRequest);
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { externalProjects: 2 });
|
||||
} as ts.server.protocol.OpenExternalProjectsRequest);
|
||||
checkNumberOfProjects(projectService, { externalProjects: 2 });
|
||||
assert.equal(projectService.externalProjects[0].getProjectName(), p1.projectFileName);
|
||||
assert.equal(projectService.externalProjects[1].getProjectName(), p3.projectFileName);
|
||||
|
||||
@@ -162,15 +164,15 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
type: "request",
|
||||
command: "openExternalProjects",
|
||||
arguments: { projects: [] }
|
||||
} as ts.projectSystem.protocol.OpenExternalProjectsRequest);
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { externalProjects: 0 });
|
||||
} as ts.server.protocol.OpenExternalProjectsRequest);
|
||||
checkNumberOfProjects(projectService, { externalProjects: 0 });
|
||||
|
||||
session.executeCommand({
|
||||
seq: 3,
|
||||
type: "request",
|
||||
command: "openExternalProjects",
|
||||
arguments: { projects: [p2] }
|
||||
} as ts.projectSystem.protocol.OpenExternalProjectsRequest);
|
||||
} as ts.server.protocol.OpenExternalProjectsRequest);
|
||||
assert.equal(projectService.externalProjects[0].getProjectName(), p2.projectFileName);
|
||||
});
|
||||
|
||||
@@ -184,69 +186,69 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
content: "let y =1;"
|
||||
};
|
||||
const externalProjectName = "externalproject";
|
||||
const host = ts.projectSystem.createServerHost([file1, file2]);
|
||||
const projectService = ts.projectSystem.createProjectService(host);
|
||||
const host = createServerHost([file1, file2]);
|
||||
const projectService = createProjectService(host);
|
||||
projectService.openExternalProject({
|
||||
rootFiles: ts.projectSystem.toExternalFiles([file1.path, file2.path]),
|
||||
rootFiles: toExternalFiles([file1.path, file2.path]),
|
||||
options: {},
|
||||
projectFileName: externalProjectName
|
||||
});
|
||||
|
||||
ts.projectSystem.checkNumberOfExternalProjects(projectService, 1);
|
||||
ts.projectSystem.checkNumberOfInferredProjects(projectService, 0);
|
||||
checkNumberOfExternalProjects(projectService, 1);
|
||||
checkNumberOfInferredProjects(projectService, 0);
|
||||
|
||||
// open client file - should not lead to creation of inferred project
|
||||
projectService.openClientFile(file1.path, file1.content);
|
||||
ts.projectSystem.checkNumberOfExternalProjects(projectService, 1);
|
||||
ts.projectSystem.checkNumberOfInferredProjects(projectService, 0);
|
||||
checkNumberOfExternalProjects(projectService, 1);
|
||||
checkNumberOfInferredProjects(projectService, 0);
|
||||
|
||||
// close client file - external project should still exists
|
||||
projectService.closeClientFile(file1.path);
|
||||
ts.projectSystem.checkNumberOfExternalProjects(projectService, 1);
|
||||
ts.projectSystem.checkNumberOfInferredProjects(projectService, 0);
|
||||
checkNumberOfExternalProjects(projectService, 1);
|
||||
checkNumberOfInferredProjects(projectService, 0);
|
||||
|
||||
projectService.closeExternalProject(externalProjectName);
|
||||
ts.projectSystem.checkNumberOfExternalProjects(projectService, 0);
|
||||
ts.projectSystem.checkNumberOfInferredProjects(projectService, 0);
|
||||
checkNumberOfExternalProjects(projectService, 0);
|
||||
checkNumberOfInferredProjects(projectService, 0);
|
||||
});
|
||||
|
||||
it("external project for dynamic file", () => {
|
||||
const externalProjectName = "^ScriptDocument1 file1.ts";
|
||||
const externalFiles = ts.projectSystem.toExternalFiles(["^ScriptDocument1 file1.ts"]);
|
||||
const host = ts.projectSystem.createServerHost([]);
|
||||
const projectService = ts.projectSystem.createProjectService(host);
|
||||
const externalFiles = toExternalFiles(["^ScriptDocument1 file1.ts"]);
|
||||
const host = createServerHost([]);
|
||||
const projectService = createProjectService(host);
|
||||
projectService.openExternalProject({
|
||||
rootFiles: externalFiles,
|
||||
options: {},
|
||||
projectFileName: externalProjectName
|
||||
});
|
||||
|
||||
ts.projectSystem.checkNumberOfExternalProjects(projectService, 1);
|
||||
ts.projectSystem.checkNumberOfInferredProjects(projectService, 0);
|
||||
ts.projectSystem.verifyDynamic(projectService, "/^scriptdocument1 file1.ts");
|
||||
checkNumberOfExternalProjects(projectService, 1);
|
||||
checkNumberOfInferredProjects(projectService, 0);
|
||||
verifyDynamic(projectService, "/^scriptdocument1 file1.ts");
|
||||
|
||||
externalFiles[0].content = "let x =1;";
|
||||
projectService.applyChangesInOpenFiles(ts.arrayIterator(externalFiles));
|
||||
});
|
||||
|
||||
it("when file name starts with ^", () => {
|
||||
const file: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/file.ts`,
|
||||
const file: File = {
|
||||
path: `/user/username/projects/myproject/file.ts`,
|
||||
content: "const x = 10;"
|
||||
};
|
||||
const app: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/^app.ts`,
|
||||
const app: File = {
|
||||
path: `/user/username/projects/myproject/^app.ts`,
|
||||
content: "const y = 10;"
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([file, app, ts.projectSystem.libFile]);
|
||||
const service = ts.projectSystem.createProjectService(host);
|
||||
const host = createServerHost([file, app, libFile]);
|
||||
const service = createProjectService(host);
|
||||
service.openExternalProjects([{
|
||||
projectFileName: `${ts.tscWatch.projectRoot}/myproject.njsproj`,
|
||||
projectFileName: `/user/username/projects/myproject/myproject.njsproj`,
|
||||
rootFiles: [
|
||||
ts.projectSystem.toExternalFile(file.path),
|
||||
ts.projectSystem.toExternalFile(app.path)
|
||||
toExternalFile(file.path),
|
||||
toExternalFile(app.path)
|
||||
],
|
||||
options: { },
|
||||
options: {},
|
||||
}]);
|
||||
});
|
||||
|
||||
@@ -282,15 +284,15 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
content: "let z =1;"
|
||||
};
|
||||
const externalProjectName = "externalproject";
|
||||
const host = ts.projectSystem.createServerHost([file1, file2, file3, config1, config2]);
|
||||
const projectService = ts.projectSystem.createProjectService(host);
|
||||
const host = createServerHost([file1, file2, file3, config1, config2]);
|
||||
const projectService = createProjectService(host);
|
||||
projectService.openExternalProject({
|
||||
rootFiles: ts.projectSystem.toExternalFiles([config1.path, config2.path, file3.path]),
|
||||
rootFiles: toExternalFiles([config1.path, config2.path, file3.path]),
|
||||
options: {},
|
||||
projectFileName: externalProjectName
|
||||
});
|
||||
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 2 });
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 2 });
|
||||
const proj1 = projectService.configuredProjects.get(config1.path);
|
||||
const proj2 = projectService.configuredProjects.get(config2.path);
|
||||
assert.isDefined(proj1);
|
||||
@@ -298,35 +300,35 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
|
||||
// open client file - should not lead to creation of inferred project
|
||||
projectService.openClientFile(file1.path, file1.content);
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 2 });
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 2 });
|
||||
assert.strictEqual(projectService.configuredProjects.get(config1.path), proj1);
|
||||
assert.strictEqual(projectService.configuredProjects.get(config2.path), proj2);
|
||||
|
||||
projectService.openClientFile(file3.path, file3.content);
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 2, inferredProjects: 1 });
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 2, inferredProjects: 1 });
|
||||
assert.strictEqual(projectService.configuredProjects.get(config1.path), proj1);
|
||||
assert.strictEqual(projectService.configuredProjects.get(config2.path), proj2);
|
||||
|
||||
projectService.closeExternalProject(externalProjectName);
|
||||
// open file 'file1' from configured project keeps project alive
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 1 });
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 1 });
|
||||
assert.strictEqual(projectService.configuredProjects.get(config1.path), proj1);
|
||||
assert.isUndefined(projectService.configuredProjects.get(config2.path));
|
||||
|
||||
projectService.closeClientFile(file3.path);
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 1 });
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 1 });
|
||||
assert.strictEqual(projectService.configuredProjects.get(config1.path), proj1);
|
||||
assert.isUndefined(projectService.configuredProjects.get(config2.path));
|
||||
assert.isTrue(projectService.inferredProjects[0].isOrphan());
|
||||
|
||||
projectService.closeClientFile(file1.path);
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 1 });
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 1 });
|
||||
assert.strictEqual(projectService.configuredProjects.get(config1.path), proj1);
|
||||
assert.isUndefined(projectService.configuredProjects.get(config2.path));
|
||||
assert.isTrue(projectService.inferredProjects[0].isOrphan());
|
||||
|
||||
projectService.openClientFile(file2.path, file2.content);
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
assert.isUndefined(projectService.configuredProjects.get(config1.path));
|
||||
assert.isDefined(projectService.configuredProjects.get(config2.path));
|
||||
});
|
||||
@@ -341,26 +343,26 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
content: JSON.stringify({ compilerOptions: {} })
|
||||
};
|
||||
const externalProjectName = "externalproject";
|
||||
const host = ts.projectSystem.createServerHost([file1, configFile]);
|
||||
const projectService = ts.projectSystem.createProjectService(host);
|
||||
const host = createServerHost([file1, configFile]);
|
||||
const projectService = createProjectService(host);
|
||||
|
||||
projectService.openClientFile(file1.path);
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
|
||||
projectService.openExternalProject({
|
||||
rootFiles: ts.projectSystem.toExternalFiles([configFile.path]),
|
||||
rootFiles: toExternalFiles([configFile.path]),
|
||||
options: {},
|
||||
projectFileName: externalProjectName
|
||||
});
|
||||
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
|
||||
projectService.closeClientFile(file1.path);
|
||||
// configured project is alive since it is opened as part of external project
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
|
||||
projectService.closeExternalProject(externalProjectName);
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 0 });
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 0 });
|
||||
});
|
||||
|
||||
it("external project with included config file opened after configured project and then closed", () => {
|
||||
@@ -377,33 +379,33 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
content: JSON.stringify({ compilerOptions: {} })
|
||||
};
|
||||
const externalProjectName = "externalproject";
|
||||
const host = ts.projectSystem.createServerHost([file1, file2, ts.projectSystem.libFile, configFile]);
|
||||
const projectService = ts.projectSystem.createProjectService(host);
|
||||
const host = createServerHost([file1, file2, libFile, configFile]);
|
||||
const projectService = createProjectService(host);
|
||||
|
||||
projectService.openClientFile(file1.path);
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
const project = projectService.configuredProjects.get(configFile.path);
|
||||
|
||||
projectService.openExternalProject({
|
||||
rootFiles: ts.projectSystem.toExternalFiles([configFile.path]),
|
||||
rootFiles: toExternalFiles([configFile.path]),
|
||||
options: {},
|
||||
projectFileName: externalProjectName
|
||||
});
|
||||
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
assert.strictEqual(projectService.configuredProjects.get(configFile.path), project);
|
||||
|
||||
projectService.closeExternalProject(externalProjectName);
|
||||
// configured project is alive since file is still open
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
assert.strictEqual(projectService.configuredProjects.get(configFile.path), project);
|
||||
|
||||
projectService.closeClientFile(file1.path);
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
assert.strictEqual(projectService.configuredProjects.get(configFile.path), project);
|
||||
|
||||
projectService.openClientFile(file2.path);
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 1 });
|
||||
checkNumberOfProjects(projectService, { inferredProjects: 1 });
|
||||
assert.isUndefined(projectService.configuredProjects.get(configFile.path));
|
||||
});
|
||||
|
||||
@@ -416,16 +418,16 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
path: "/a/b/f2.ts",
|
||||
content: "let y = 1"
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([file1, file2]);
|
||||
const projectService = ts.projectSystem.createProjectService(host);
|
||||
const host = createServerHost([file1, file2]);
|
||||
const projectService = createProjectService(host);
|
||||
|
||||
projectService.openExternalProject({ projectFileName: "project", options: {}, rootFiles: ts.projectSystem.toExternalFiles([file1.path]) });
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { externalProjects: 1 });
|
||||
ts.projectSystem.checkProjectActualFiles(projectService.externalProjects[0], [file1.path]);
|
||||
projectService.openExternalProject({ projectFileName: "project", options: {}, rootFiles: toExternalFiles([file1.path]) });
|
||||
checkNumberOfProjects(projectService, { externalProjects: 1 });
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [file1.path]);
|
||||
|
||||
projectService.openExternalProject({ projectFileName: "project", options: {}, rootFiles: ts.projectSystem.toExternalFiles([file1.path, file2.path]) });
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { externalProjects: 1 });
|
||||
ts.projectSystem.checkProjectRootFiles(projectService.externalProjects[0], [file1.path, file2.path]);
|
||||
projectService.openExternalProject({ projectFileName: "project", options: {}, rootFiles: toExternalFiles([file1.path, file2.path]) });
|
||||
checkNumberOfProjects(projectService, { externalProjects: 1 });
|
||||
checkProjectRootFiles(projectService.externalProjects[0], [file1.path, file2.path]);
|
||||
});
|
||||
|
||||
it("can update external project when set of root files was not changed", () => {
|
||||
@@ -442,18 +444,18 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
content: "export let y = 1"
|
||||
};
|
||||
|
||||
const host = ts.projectSystem.createServerHost([file1, file2, file3]);
|
||||
const projectService = ts.projectSystem.createProjectService(host);
|
||||
const host = createServerHost([file1, file2, file3]);
|
||||
const projectService = createProjectService(host);
|
||||
|
||||
projectService.openExternalProject({ projectFileName: "project", options: { moduleResolution: ts.ModuleResolutionKind.NodeJs }, rootFiles: ts.projectSystem.toExternalFiles([file1.path, file2.path]) });
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { externalProjects: 1 });
|
||||
ts.projectSystem.checkProjectRootFiles(projectService.externalProjects[0], [file1.path, file2.path]);
|
||||
ts.projectSystem.checkProjectActualFiles(projectService.externalProjects[0], [file1.path, file2.path]);
|
||||
projectService.openExternalProject({ projectFileName: "project", options: { moduleResolution: ts.ModuleResolutionKind.NodeJs }, rootFiles: toExternalFiles([file1.path, file2.path]) });
|
||||
checkNumberOfProjects(projectService, { externalProjects: 1 });
|
||||
checkProjectRootFiles(projectService.externalProjects[0], [file1.path, file2.path]);
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [file1.path, file2.path]);
|
||||
|
||||
projectService.openExternalProject({ projectFileName: "project", options: { moduleResolution: ts.ModuleResolutionKind.Classic }, rootFiles: ts.projectSystem.toExternalFiles([file1.path, file2.path]) });
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { externalProjects: 1 });
|
||||
ts.projectSystem.checkProjectRootFiles(projectService.externalProjects[0], [file1.path, file2.path]);
|
||||
ts.projectSystem.checkProjectActualFiles(projectService.externalProjects[0], [file1.path, file2.path, file3.path]);
|
||||
projectService.openExternalProject({ projectFileName: "project", options: { moduleResolution: ts.ModuleResolutionKind.Classic }, rootFiles: toExternalFiles([file1.path, file2.path]) });
|
||||
checkNumberOfProjects(projectService, { externalProjects: 1 });
|
||||
checkProjectRootFiles(projectService.externalProjects[0], [file1.path, file2.path]);
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [file1.path, file2.path, file3.path]);
|
||||
});
|
||||
|
||||
it("language service disabled state is updated in external projects", () => {
|
||||
@@ -465,17 +467,17 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
path: "/a/largefile.js",
|
||||
content: ""
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([f1, f2]);
|
||||
const host = createServerHost([f1, f2]);
|
||||
const originalGetFileSize = host.getFileSize;
|
||||
host.getFileSize = (filePath: string) =>
|
||||
filePath === f2.path ? ts.server.maxProgramSizeForNonTsFiles + 1 : originalGetFileSize.call(host, filePath);
|
||||
|
||||
const service = ts.projectSystem.createProjectService(host);
|
||||
const service = createProjectService(host);
|
||||
const projectFileName = "/a/proj.csproj";
|
||||
|
||||
service.openExternalProject({
|
||||
projectFileName,
|
||||
rootFiles: ts.projectSystem.toExternalFiles([f1.path, f2.path]),
|
||||
rootFiles: toExternalFiles([f1.path, f2.path]),
|
||||
options: {}
|
||||
});
|
||||
service.checkNumberOfProjects({ externalProjects: 1 });
|
||||
@@ -483,7 +485,7 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
|
||||
service.openExternalProject({
|
||||
projectFileName,
|
||||
rootFiles: ts.projectSystem.toExternalFiles([f1.path]),
|
||||
rootFiles: toExternalFiles([f1.path]),
|
||||
options: {}
|
||||
});
|
||||
service.checkNumberOfProjects({ externalProjects: 1 });
|
||||
@@ -491,7 +493,7 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
|
||||
service.openExternalProject({
|
||||
projectFileName,
|
||||
rootFiles: ts.projectSystem.toExternalFiles([f1.path, f2.path]),
|
||||
rootFiles: toExternalFiles([f1.path, f2.path]),
|
||||
options: {}
|
||||
});
|
||||
service.checkNumberOfProjects({ externalProjects: 1 });
|
||||
@@ -509,13 +511,13 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
content: "{}"
|
||||
};
|
||||
const projectFileName = "/user/someuser/project/WebApplication6.csproj";
|
||||
const host = ts.projectSystem.createServerHost([ts.projectSystem.libFile, site, configFile]);
|
||||
const projectService = ts.projectSystem.createProjectService(host);
|
||||
const host = createServerHost([libFile, site, configFile]);
|
||||
const projectService = createProjectService(host);
|
||||
projectService.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject } });
|
||||
|
||||
const externalProject: ts.projectSystem.protocol.ExternalProject = {
|
||||
const externalProject: ts.server.protocol.ExternalProject = {
|
||||
projectFileName,
|
||||
rootFiles: [ts.projectSystem.toExternalFile(site.path), ts.projectSystem.toExternalFile(configFile.path)],
|
||||
rootFiles: [toExternalFile(site.path), toExternalFile(configFile.path)],
|
||||
options: { allowJs: false },
|
||||
typeAcquisition: { include: [] }
|
||||
};
|
||||
@@ -523,23 +525,23 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
projectService.openExternalProjects([externalProject]);
|
||||
|
||||
let knownProjects = projectService.synchronizeProjectList([]);
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1, externalProjects: 0, inferredProjects: 0 });
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1, externalProjects: 0, inferredProjects: 0 });
|
||||
|
||||
const configProject = ts.projectSystem.configuredProjectAt(projectService, 0);
|
||||
ts.projectSystem.checkProjectActualFiles(configProject, lazyConfiguredProjectsFromExternalProject ?
|
||||
const configProject = configuredProjectAt(projectService, 0);
|
||||
checkProjectActualFiles(configProject, lazyConfiguredProjectsFromExternalProject ?
|
||||
ts.emptyArray : // Since no files opened from this project, its not loaded
|
||||
[configFile.path]);
|
||||
|
||||
host.deleteFile(configFile.path);
|
||||
|
||||
knownProjects = projectService.synchronizeProjectList(ts.map(knownProjects, proj => proj.info!)); // TODO: GH#18217 GH#20039
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 0, externalProjects: 0, inferredProjects: 0 });
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 0, externalProjects: 0, inferredProjects: 0 });
|
||||
|
||||
externalProject.rootFiles.length = 1;
|
||||
projectService.openExternalProjects([externalProject]);
|
||||
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 0, externalProjects: 1, inferredProjects: 0 });
|
||||
ts.projectSystem.checkProjectActualFiles(projectService.externalProjects[0], [site.path, ts.projectSystem.libFile.path]);
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 0, externalProjects: 1, inferredProjects: 0 });
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [site.path, libFile.path]);
|
||||
}
|
||||
it("when lazyConfiguredProjectsFromExternalProject not set", () => {
|
||||
verifyDeletingConfigFile(/*lazyConfiguredProjectsFromExternalProject*/ false);
|
||||
@@ -563,45 +565,45 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: ""
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([f1, f2]);
|
||||
const projectService = ts.projectSystem.createProjectService(host);
|
||||
const host = createServerHost([f1, f2]);
|
||||
const projectService = createProjectService(host);
|
||||
projectService.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject } });
|
||||
|
||||
// open external project
|
||||
const projectName = "/a/b/proj1";
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: ts.projectSystem.toExternalFiles([f1.path, f2.path]),
|
||||
rootFiles: toExternalFiles([f1.path, f2.path]),
|
||||
options: {}
|
||||
});
|
||||
projectService.openClientFile(f1.path);
|
||||
projectService.checkNumberOfProjects({ externalProjects: 1 });
|
||||
ts.projectSystem.checkProjectActualFiles(projectService.externalProjects[0], [f1.path, f2.path]);
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [f1.path, f2.path]);
|
||||
|
||||
// rename lib.ts to tsconfig.json
|
||||
host.renameFile(f2.path, tsconfig.path);
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: ts.projectSystem.toExternalFiles([f1.path, tsconfig.path]),
|
||||
rootFiles: toExternalFiles([f1.path, tsconfig.path]),
|
||||
options: {}
|
||||
});
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
if (lazyConfiguredProjectsFromExternalProject) {
|
||||
ts.projectSystem.checkProjectActualFiles(ts.projectSystem.configuredProjectAt(projectService, 0), ts.emptyArray); // Configured project created but not loaded till actually needed
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), ts.emptyArray); // Configured project created but not loaded till actually needed
|
||||
projectService.ensureInferredProjectsUpToDate_TestOnly();
|
||||
}
|
||||
ts.projectSystem.checkProjectActualFiles(ts.projectSystem.configuredProjectAt(projectService, 0), [f1.path, tsconfig.path]);
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), [f1.path, tsconfig.path]);
|
||||
|
||||
// rename tsconfig.json back to lib.ts
|
||||
host.renameFile(tsconfig.path, f2.path);
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: ts.projectSystem.toExternalFiles([f1.path, f2.path]),
|
||||
rootFiles: toExternalFiles([f1.path, f2.path]),
|
||||
options: {}
|
||||
});
|
||||
|
||||
projectService.checkNumberOfProjects({ externalProjects: 1 });
|
||||
ts.projectSystem.checkProjectActualFiles(projectService.externalProjects[0], [f1.path, f2.path]);
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [f1.path, f2.path]);
|
||||
}
|
||||
it("when lazyConfiguredProjectsFromExternalProject not set", () => {
|
||||
verifyAddRemoveConfig(/*lazyConfiguredProjectsFromExternalProject*/ false);
|
||||
@@ -633,71 +635,71 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
path: "/a/b/d/tsconfig.json",
|
||||
content: "{}"
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([f1, cLib, cTsconfig, dLib, dTsconfig]);
|
||||
const projectService = ts.projectSystem.createProjectService(host);
|
||||
const host = createServerHost([f1, cLib, cTsconfig, dLib, dTsconfig]);
|
||||
const projectService = createProjectService(host);
|
||||
projectService.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject } });
|
||||
|
||||
// open external project
|
||||
const projectName = "/a/b/proj1";
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: ts.projectSystem.toExternalFiles([f1.path]),
|
||||
rootFiles: toExternalFiles([f1.path]),
|
||||
options: {}
|
||||
});
|
||||
|
||||
projectService.checkNumberOfProjects({ externalProjects: 1 });
|
||||
ts.projectSystem.checkProjectActualFiles(projectService.externalProjects[0], [f1.path]);
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [f1.path]);
|
||||
|
||||
// add two config file as root files
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: ts.projectSystem.toExternalFiles([f1.path, cTsconfig.path, dTsconfig.path]),
|
||||
rootFiles: toExternalFiles([f1.path, cTsconfig.path, dTsconfig.path]),
|
||||
options: {}
|
||||
});
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 2 });
|
||||
if (lazyConfiguredProjectsFromExternalProject) {
|
||||
ts.projectSystem.checkProjectActualFiles(ts.projectSystem.configuredProjectAt(projectService, 0), ts.emptyArray); // Configured project created but not loaded till actually needed
|
||||
ts.projectSystem.checkProjectActualFiles(ts.projectSystem.configuredProjectAt(projectService, 1), ts.emptyArray); // Configured project created but not loaded till actually needed
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), ts.emptyArray); // Configured project created but not loaded till actually needed
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 1), ts.emptyArray); // Configured project created but not loaded till actually needed
|
||||
projectService.ensureInferredProjectsUpToDate_TestOnly();
|
||||
}
|
||||
ts.projectSystem.checkProjectActualFiles(ts.projectSystem.configuredProjectAt(projectService, 0), [cLib.path, cTsconfig.path]);
|
||||
ts.projectSystem.checkProjectActualFiles(ts.projectSystem.configuredProjectAt(projectService, 1), [dLib.path, dTsconfig.path]);
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), [cLib.path, cTsconfig.path]);
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 1), [dLib.path, dTsconfig.path]);
|
||||
|
||||
// remove one config file
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: ts.projectSystem.toExternalFiles([f1.path, dTsconfig.path]),
|
||||
rootFiles: toExternalFiles([f1.path, dTsconfig.path]),
|
||||
options: {}
|
||||
});
|
||||
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
ts.projectSystem.checkProjectActualFiles(ts.projectSystem.configuredProjectAt(projectService, 0), [dLib.path, dTsconfig.path]);
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), [dLib.path, dTsconfig.path]);
|
||||
|
||||
// remove second config file
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: ts.projectSystem.toExternalFiles([f1.path]),
|
||||
rootFiles: toExternalFiles([f1.path]),
|
||||
options: {}
|
||||
});
|
||||
|
||||
projectService.checkNumberOfProjects({ externalProjects: 1 });
|
||||
ts.projectSystem.checkProjectActualFiles(projectService.externalProjects[0], [f1.path]);
|
||||
checkProjectActualFiles(projectService.externalProjects[0], [f1.path]);
|
||||
|
||||
// open two config files
|
||||
// add two config file as root files
|
||||
projectService.openExternalProject({
|
||||
projectFileName: projectName,
|
||||
rootFiles: ts.projectSystem.toExternalFiles([f1.path, cTsconfig.path, dTsconfig.path]),
|
||||
rootFiles: toExternalFiles([f1.path, cTsconfig.path, dTsconfig.path]),
|
||||
options: {}
|
||||
});
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 2 });
|
||||
if (lazyConfiguredProjectsFromExternalProject) {
|
||||
ts.projectSystem.checkProjectActualFiles(ts.projectSystem.configuredProjectAt(projectService, 0), ts.emptyArray); // Configured project created but not loaded till actually needed
|
||||
ts.projectSystem.checkProjectActualFiles(ts.projectSystem.configuredProjectAt(projectService, 1), ts.emptyArray); // Configured project created but not loaded till actually needed
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), ts.emptyArray); // Configured project created but not loaded till actually needed
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 1), ts.emptyArray); // Configured project created but not loaded till actually needed
|
||||
projectService.ensureInferredProjectsUpToDate_TestOnly();
|
||||
}
|
||||
ts.projectSystem.checkProjectActualFiles(ts.projectSystem.configuredProjectAt(projectService, 0), [cLib.path, cTsconfig.path]);
|
||||
ts.projectSystem.checkProjectActualFiles(ts.projectSystem.configuredProjectAt(projectService, 1), [dLib.path, dTsconfig.path]);
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), [cLib.path, cTsconfig.path]);
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 1), [dLib.path, dTsconfig.path]);
|
||||
|
||||
// close all projects - no projects should be opened
|
||||
projectService.closeExternalProject(projectName);
|
||||
@@ -756,18 +758,18 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
}
|
||||
})
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([libES5, libES2015Promise, app, config1], { executingFilePath: "/compiler/tsc.js" });
|
||||
const projectService = ts.projectSystem.createProjectService(host);
|
||||
const host = createServerHost([libES5, libES2015Promise, app, config1], { executingFilePath: "/compiler/tsc.js" });
|
||||
const projectService = createProjectService(host);
|
||||
projectService.openClientFile(app.path);
|
||||
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
ts.projectSystem.checkProjectActualFiles(ts.projectSystem.configuredProjectAt(projectService, 0), [libES5.path, app.path, config1.path]);
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), [libES5.path, app.path, config1.path]);
|
||||
|
||||
host.writeFile(config2.path, config2.content);
|
||||
host.checkTimeoutQueueLengthAndRun(2);
|
||||
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
ts.projectSystem.checkProjectActualFiles(ts.projectSystem.configuredProjectAt(projectService, 0), [libES5.path, libES2015Promise.path, app.path, config2.path]);
|
||||
checkProjectActualFiles(configuredProjectAt(projectService, 0), [libES5.path, libES2015Promise.path, app.path, config2.path]);
|
||||
});
|
||||
|
||||
it("should handle non-existing directories in config file", () => {
|
||||
@@ -785,8 +787,8 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
]
|
||||
})
|
||||
};
|
||||
const host = ts.projectSystem.createServerHost([f, config]);
|
||||
const projectService = ts.projectSystem.createProjectService(host);
|
||||
const host = createServerHost([f, config]);
|
||||
const projectService = createProjectService(host);
|
||||
projectService.openClientFile(f.path);
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
const project = projectService.configuredProjects.get(config.path)!;
|
||||
@@ -815,46 +817,46 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
content: JSON.stringify({})
|
||||
};
|
||||
const projectFileName = "/a/b/project.csproj";
|
||||
const host = ts.projectSystem.createServerHost([f1, config]);
|
||||
const service = ts.projectSystem.createProjectService(host);
|
||||
const host = createServerHost([f1, config]);
|
||||
const service = createProjectService(host);
|
||||
service.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject: true } });
|
||||
service.openExternalProject({
|
||||
projectFileName,
|
||||
rootFiles: ts.projectSystem.toExternalFiles([f1.path, config.path]),
|
||||
rootFiles: toExternalFiles([f1.path, config.path]),
|
||||
options: {}
|
||||
} as ts.projectSystem.protocol.ExternalProject);
|
||||
} as ts.server.protocol.ExternalProject);
|
||||
service.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
const project = service.configuredProjects.get(config.path)!;
|
||||
assert.equal(project.pendingReload, ts.ConfigFileProgramReloadLevel.Full); // External project referenced configured project pending to be reloaded
|
||||
ts.projectSystem.checkProjectActualFiles(project, ts.emptyArray);
|
||||
checkProjectActualFiles(project, ts.emptyArray);
|
||||
|
||||
service.setHostConfiguration({ preferences: { lazyConfiguredProjectsFromExternalProject: false } });
|
||||
assert.equal(project.pendingReload, ts.ConfigFileProgramReloadLevel.None); // External project referenced configured project loaded
|
||||
ts.projectSystem.checkProjectActualFiles(project, [config.path, f1.path]);
|
||||
checkProjectActualFiles(project, [config.path, f1.path]);
|
||||
|
||||
service.closeExternalProject(projectFileName);
|
||||
service.checkNumberOfProjects({});
|
||||
|
||||
service.openExternalProject({
|
||||
projectFileName,
|
||||
rootFiles: ts.projectSystem.toExternalFiles([f1.path, config.path]),
|
||||
rootFiles: toExternalFiles([f1.path, config.path]),
|
||||
options: {}
|
||||
} as ts.projectSystem.protocol.ExternalProject);
|
||||
} as ts.server.protocol.ExternalProject);
|
||||
service.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
const project2 = service.configuredProjects.get(config.path)!;
|
||||
assert.equal(project2.pendingReload, ts.ConfigFileProgramReloadLevel.None); // External project referenced configured project loaded
|
||||
ts.projectSystem.checkProjectActualFiles(project2, [config.path, f1.path]);
|
||||
checkProjectActualFiles(project2, [config.path, f1.path]);
|
||||
});
|
||||
|
||||
it("handles creation of external project with jsconfig before jsconfig creation watcher is invoked", () => {
|
||||
const projectFileName = `${ts.tscWatch.projectRoot}/WebApplication36.csproj`;
|
||||
const tsconfig: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const projectFileName = `/user/username/projects/myproject/WebApplication36.csproj`;
|
||||
const tsconfig: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: "{}"
|
||||
};
|
||||
const files = [ts.projectSystem.libFile, tsconfig];
|
||||
const host = ts.projectSystem.createServerHost(files);
|
||||
const service = ts.projectSystem.createProjectService(host);
|
||||
const files = [libFile, tsconfig];
|
||||
const host = createServerHost(files);
|
||||
const service = createProjectService(host);
|
||||
|
||||
// Create external project
|
||||
service.openExternalProjects([{
|
||||
@@ -862,12 +864,12 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
rootFiles: [{ fileName: tsconfig.path }],
|
||||
options: { allowJs: false }
|
||||
}]);
|
||||
ts.projectSystem.checkNumberOfProjects(service, { configuredProjects: 1 });
|
||||
checkNumberOfProjects(service, { configuredProjects: 1 });
|
||||
const configProject = service.configuredProjects.get(tsconfig.path.toLowerCase())!;
|
||||
ts.projectSystem.checkProjectActualFiles(configProject, [tsconfig.path]);
|
||||
checkProjectActualFiles(configProject, [tsconfig.path]);
|
||||
|
||||
// write js file, open external project and open it for edit
|
||||
const jsFilePath = `${ts.tscWatch.projectRoot}/javascript.js`;
|
||||
const jsFilePath = `/user/username/projects/myproject/javascript.js`;
|
||||
host.writeFile(jsFilePath, "");
|
||||
service.openExternalProjects([{
|
||||
projectFileName,
|
||||
@@ -875,14 +877,14 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
options: { allowJs: false }
|
||||
}]);
|
||||
service.applyChangesInOpenFiles(ts.singleIterator({ fileName: jsFilePath, scriptKind: ts.ScriptKind.JS, content: "" }));
|
||||
ts.projectSystem.checkNumberOfProjects(service, { configuredProjects: 1, inferredProjects: 1 });
|
||||
ts.projectSystem.checkProjectActualFiles(configProject, [tsconfig.path]);
|
||||
checkNumberOfProjects(service, { configuredProjects: 1, inferredProjects: 1 });
|
||||
checkProjectActualFiles(configProject, [tsconfig.path]);
|
||||
const inferredProject = service.inferredProjects[0];
|
||||
ts.projectSystem.checkProjectActualFiles(inferredProject, [ts.projectSystem.libFile.path, jsFilePath]);
|
||||
checkProjectActualFiles(inferredProject, [libFile.path, jsFilePath]);
|
||||
|
||||
// write jsconfig file
|
||||
const jsConfig: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/jsconfig.json`,
|
||||
const jsConfig: File = {
|
||||
path: `/user/username/projects/myproject/jsconfig.json`,
|
||||
content: "{}"
|
||||
};
|
||||
// Dont invoke file creation watchers as the repro suggests
|
||||
@@ -894,11 +896,11 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
rootFiles: [{ fileName: jsConfig.path }, { fileName: tsconfig.path }, { fileName: jsFilePath }],
|
||||
options: { allowJs: false }
|
||||
}]);
|
||||
ts.projectSystem.checkNumberOfProjects(service, { configuredProjects: 2, inferredProjects: 1 });
|
||||
ts.projectSystem.checkProjectActualFiles(configProject, [tsconfig.path]);
|
||||
checkNumberOfProjects(service, { configuredProjects: 2, inferredProjects: 1 });
|
||||
checkProjectActualFiles(configProject, [tsconfig.path]);
|
||||
assert.isTrue(inferredProject.isOrphan());
|
||||
const jsConfigProject = service.configuredProjects.get(jsConfig.path.toLowerCase())!;
|
||||
ts.projectSystem.checkProjectActualFiles(jsConfigProject, [jsConfig.path, jsFilePath, ts.projectSystem.libFile.path]);
|
||||
checkProjectActualFiles(jsConfigProject, [jsConfig.path, jsFilePath, libFile.path]);
|
||||
});
|
||||
|
||||
it("does not crash if external file does not exist", () => {
|
||||
@@ -908,11 +910,11 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
};
|
||||
const p1 = {
|
||||
projectFileName: "/a/proj1.csproj",
|
||||
rootFiles: [ts.projectSystem.toExternalFile(f1.path)],
|
||||
rootFiles: [toExternalFile(f1.path)],
|
||||
options: {},
|
||||
};
|
||||
|
||||
const host = ts.projectSystem.createServerHost([f1]);
|
||||
const host = createServerHost([f1]);
|
||||
host.require = (_initialPath, moduleName) => {
|
||||
assert.equal(moduleName, "myplugin");
|
||||
return {
|
||||
@@ -927,7 +929,7 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
error: undefined,
|
||||
};
|
||||
};
|
||||
const session = ts.projectSystem.createSession(host, {
|
||||
const session = createSession(host, {
|
||||
globalPlugins: ["myplugin"],
|
||||
});
|
||||
const projectService = session.getProjectService();
|
||||
@@ -937,6 +939,6 @@ describe("unittests:: tsserver:: ExternalProjects", () => {
|
||||
// info for it. If tsserver does not handle this case, the following
|
||||
// method call will crash.
|
||||
projectService.openExternalProject(p1);
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { externalProjects: 1 });
|
||||
checkNumberOfProjects(projectService, { externalProjects: 1 });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { createServerHost, File, libFile } from "../virtualFileSystemWithWatch";
|
||||
import { createSession, openFilesForSession, checkNumberOfProjects, configuredProjectAt, createLoggerWithInMemoryLogs, verifyGetErrRequest, closeFilesForSession, protocolTextSpanFromSubstring, baselineTsserverLogs } from "./helpers";
|
||||
|
||||
describe("unittests:: tsserver:: forceConsistentCasingInFileNames", () => {
|
||||
it("works when extends is specified with a case insensitive file system", () => {
|
||||
const rootPath = "/Users/username/dev/project";
|
||||
const file1: ts.projectSystem.File = {
|
||||
const file1: File = {
|
||||
path: `${rootPath}/index.ts`,
|
||||
content: 'import {x} from "file2";',
|
||||
};
|
||||
const file2: ts.projectSystem.File = {
|
||||
const file2: File = {
|
||||
path: `${rootPath}/file2.js`,
|
||||
content: "",
|
||||
};
|
||||
const file2Dts: ts.projectSystem.File = {
|
||||
const file2Dts: File = {
|
||||
path: `${rootPath}/types/file2/index.d.ts`,
|
||||
content: "export declare const x: string;",
|
||||
};
|
||||
const tsconfigAll: ts.projectSystem.File = {
|
||||
const tsconfigAll: File = {
|
||||
path: `${rootPath}/tsconfig.all.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
@@ -26,59 +28,59 @@ describe("unittests:: tsserver:: forceConsistentCasingInFileNames", () => {
|
||||
},
|
||||
}),
|
||||
};
|
||||
const tsconfig: ts.projectSystem.File = {
|
||||
const tsconfig: File = {
|
||||
path: `${rootPath}/tsconfig.json`,
|
||||
content: JSON.stringify({ extends: "./tsconfig.all.json" }),
|
||||
};
|
||||
|
||||
const host = ts.projectSystem.createServerHost([file1, file2, file2Dts, ts.projectSystem.libFile, tsconfig, tsconfigAll], { useCaseSensitiveFileNames: false });
|
||||
const session = ts.projectSystem.createSession(host);
|
||||
const host = createServerHost([file1, file2, file2Dts, libFile, tsconfig, tsconfigAll], { useCaseSensitiveFileNames: false });
|
||||
const session = createSession(host);
|
||||
|
||||
ts.projectSystem.openFilesForSession([file1], session);
|
||||
openFilesForSession([file1], session);
|
||||
const projectService = session.getProjectService();
|
||||
|
||||
ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
|
||||
const diagnostics = ts.projectSystem.configuredProjectAt(projectService, 0).getLanguageService().getCompilerOptionsDiagnostics();
|
||||
const diagnostics = configuredProjectAt(projectService, 0).getLanguageService().getCompilerOptionsDiagnostics();
|
||||
assert.deepEqual(diagnostics, []);
|
||||
});
|
||||
|
||||
it("works when renaming file with different casing", () => {
|
||||
const loggerFile: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/Logger.ts`,
|
||||
const loggerFile: File = {
|
||||
path: `/user/username/projects/myproject/Logger.ts`,
|
||||
content: `export class logger { }`
|
||||
};
|
||||
const anotherFile: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/another.ts`,
|
||||
const anotherFile: File = {
|
||||
path: `/user/username/projects/myproject/another.ts`,
|
||||
content: `import { logger } from "./Logger"; new logger();`
|
||||
};
|
||||
const tsconfig: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const tsconfig: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { forceConsistentCasingInFileNames: true }
|
||||
})
|
||||
};
|
||||
|
||||
const host = ts.projectSystem.createServerHost([loggerFile, anotherFile, tsconfig, ts.projectSystem.libFile, tsconfig]);
|
||||
const session = ts.projectSystem.createSession(host, { canUseEvents: true, logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) });
|
||||
ts.projectSystem.openFilesForSession([{ file: loggerFile, projectRootPath: ts.tscWatch.projectRoot }], session);
|
||||
ts.projectSystem.verifyGetErrRequest({ session, host, files: [loggerFile] });
|
||||
const host = createServerHost([loggerFile, anotherFile, tsconfig, libFile, tsconfig]);
|
||||
const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) });
|
||||
openFilesForSession([{ file: loggerFile, projectRootPath: "/user/username/projects/myproject" }], session);
|
||||
verifyGetErrRequest({ session, host, files: [loggerFile] });
|
||||
|
||||
const newLoggerPath = loggerFile.path.toLowerCase();
|
||||
host.renameFile(loggerFile.path, newLoggerPath);
|
||||
ts.projectSystem.closeFilesForSession([loggerFile], session);
|
||||
ts.projectSystem.openFilesForSession([{ file: newLoggerPath, content: loggerFile.content, projectRootPath: ts.tscWatch.projectRoot }], session);
|
||||
closeFilesForSession([loggerFile], session);
|
||||
openFilesForSession([{ file: newLoggerPath, content: loggerFile.content, projectRootPath: "/user/username/projects/myproject" }], session);
|
||||
|
||||
// Apply edits for rename
|
||||
ts.projectSystem.openFilesForSession([{ file: anotherFile, projectRootPath: ts.tscWatch.projectRoot }], session);
|
||||
session.executeCommandSeq<ts.projectSystem.protocol.UpdateOpenRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.UpdateOpen,
|
||||
openFilesForSession([{ file: anotherFile, projectRootPath: "/user/username/projects/myproject" }], session);
|
||||
session.executeCommandSeq<ts.server.protocol.UpdateOpenRequest>({
|
||||
command: ts.server.protocol.CommandTypes.UpdateOpen,
|
||||
arguments: {
|
||||
changedFiles: [{
|
||||
fileName: anotherFile.path,
|
||||
textChanges: [{
|
||||
newText: "./logger",
|
||||
...ts.projectSystem.protocolTextSpanFromSubstring(
|
||||
...protocolTextSpanFromSubstring(
|
||||
anotherFile.content,
|
||||
"./Logger"
|
||||
)
|
||||
@@ -88,39 +90,39 @@ describe("unittests:: tsserver:: forceConsistentCasingInFileNames", () => {
|
||||
});
|
||||
|
||||
// Check errors in both files
|
||||
ts.projectSystem.verifyGetErrRequest({ session, host, files: [newLoggerPath, anotherFile] });
|
||||
ts.projectSystem.baselineTsserverLogs("forceConsistentCasingInFileNames", "works when renaming file with different casing", session);
|
||||
verifyGetErrRequest({ session, host, files: [newLoggerPath, anotherFile] });
|
||||
baselineTsserverLogs("forceConsistentCasingInFileNames", "works when renaming file with different casing", session);
|
||||
});
|
||||
|
||||
it("when changing module name with different casing", () => {
|
||||
const loggerFile: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/Logger.ts`,
|
||||
const loggerFile: File = {
|
||||
path: `/user/username/projects/myproject/Logger.ts`,
|
||||
content: `export class logger { }`
|
||||
};
|
||||
const anotherFile: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/another.ts`,
|
||||
const anotherFile: File = {
|
||||
path: `/user/username/projects/myproject/another.ts`,
|
||||
content: `import { logger } from "./Logger"; new logger();`
|
||||
};
|
||||
const tsconfig: ts.projectSystem.File = {
|
||||
path: `${ts.tscWatch.projectRoot}/tsconfig.json`,
|
||||
const tsconfig: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { forceConsistentCasingInFileNames: true }
|
||||
})
|
||||
};
|
||||
|
||||
const host = ts.projectSystem.createServerHost([loggerFile, anotherFile, tsconfig, ts.projectSystem.libFile, tsconfig]);
|
||||
const session = ts.projectSystem.createSession(host, { canUseEvents: true, logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) });
|
||||
ts.projectSystem.openFilesForSession([{ file: anotherFile, projectRootPath: ts.tscWatch.projectRoot }], session);
|
||||
ts.projectSystem.verifyGetErrRequest({ session, host, files: [anotherFile] });
|
||||
const host = createServerHost([loggerFile, anotherFile, tsconfig, libFile, tsconfig]);
|
||||
const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) });
|
||||
openFilesForSession([{ file: anotherFile, projectRootPath: "/user/username/projects/myproject" }], session);
|
||||
verifyGetErrRequest({ session, host, files: [anotherFile] });
|
||||
|
||||
session.executeCommandSeq<ts.projectSystem.protocol.UpdateOpenRequest>({
|
||||
command: ts.projectSystem.protocol.CommandTypes.UpdateOpen,
|
||||
session.executeCommandSeq<ts.server.protocol.UpdateOpenRequest>({
|
||||
command: ts.server.protocol.CommandTypes.UpdateOpen,
|
||||
arguments: {
|
||||
changedFiles: [{
|
||||
fileName: anotherFile.path,
|
||||
textChanges: [{
|
||||
newText: "./logger",
|
||||
...ts.projectSystem.protocolTextSpanFromSubstring(
|
||||
...protocolTextSpanFromSubstring(
|
||||
anotherFile.content,
|
||||
"./Logger"
|
||||
)
|
||||
@@ -130,7 +132,7 @@ describe("unittests:: tsserver:: forceConsistentCasingInFileNames", () => {
|
||||
});
|
||||
|
||||
// Check errors in both files
|
||||
ts.projectSystem.verifyGetErrRequest({ host, session, files: [anotherFile] });
|
||||
ts.projectSystem.baselineTsserverLogs("forceConsistentCasingInFileNames", "when changing module name with different casing", session);
|
||||
verifyGetErrRequest({ host, session, files: [anotherFile] });
|
||||
baselineTsserverLogs("forceConsistentCasingInFileNames", "when changing module name with different casing", session);
|
||||
});
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user