From 6a3b4991f0bb8534fcdcbaa882719c2517dc81d0 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Tue, 8 Nov 2022 12:23:30 -0800 Subject: [PATCH 01/11] Remove leftover todo from mjs/cjs transition (#51453) --- scripts/failed-tests.cjs | 2 +- scripts/failed-tests.d.cts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/failed-tests.cjs b/scripts/failed-tests.cjs index d2f3078e7b7..b669db47c03 100644 --- a/scripts/failed-tests.cjs +++ b/scripts/failed-tests.cjs @@ -8,7 +8,7 @@ const os = require("os"); file?: string; keepFailed?: boolean; reporter?: Mocha.ReporterConstructor | keyof Mocha.reporters; - reporterOptions?: any; // TODO(jakebailey): what? + reporterOptions?: any; }} ReporterOptions */ void 0; diff --git a/scripts/failed-tests.d.cts b/scripts/failed-tests.d.cts index 2978fb81758..9c7ee986ec0 100644 --- a/scripts/failed-tests.d.cts +++ b/scripts/failed-tests.d.cts @@ -3,7 +3,7 @@ export = FailedTestsReporter; file?: string; keepFailed?: boolean; reporter?: Mocha.ReporterConstructor | keyof Mocha.reporters; - reporterOptions?: any; // TODO(jakebailey): what? + reporterOptions?: any; }} ReporterOptions */ /** * .failed-tests reporter From b4715d38911dcdaa24c942450716b79173e0bb1d Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Tue, 8 Nov 2022 13:59:48 -0800 Subject: [PATCH 02/11] Replace eslint-plugin-jsdoc by extending local jsdoc-format rule, saving ~20% of our linting time (#51438) --- .eslintrc.json | 5 +- package-lock.json | 136 -------------------------- package.json | 1 - scripts/eslint/rules/jsdoc-format.cjs | 107 ++++++++++++++++---- 4 files changed, 88 insertions(+), 161 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index f78f3250020..2b6afe437b0 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -10,7 +10,7 @@ "es6": true }, "plugins": [ - "@typescript-eslint", "jsdoc", "no-null", "import", "eslint-plugin-local" + "@typescript-eslint", "no-null", "import", "eslint-plugin-local" ], "rules": { "@typescript-eslint/adjacent-overload-signatures": "error", @@ -95,9 +95,6 @@ // eslint-plugin-no-null "no-null/no-null": "error", - // eslint-plugin-jsdoc - "jsdoc/check-alignment": "error", - // eslint "constructor-super": "error", "curly": ["error", "multi-line"], diff --git a/package-lock.json b/package-lock.json index 9fa34faf23d..a093d15787f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,7 +36,6 @@ "eslint": "^8.22.0", "eslint-formatter-autolinkable-stylish": "^1.2.0", "eslint-plugin-import": "^2.26.0", - "eslint-plugin-jsdoc": "^39.3.6", "eslint-plugin-local": "^1.0.0", "eslint-plugin-no-null": "^1.0.2", "fast-xml-parser": "^4.0.11", @@ -57,20 +56,6 @@ "node": ">=4.2.0" } }, - "node_modules/@es-joy/jsdoccomment": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.36.0.tgz", - "integrity": "sha512-u0XZyvUF6Urb2cSivSXA8qXIpT/CxkHcdtZKoWusAzgzmsTWpg0F2FpWXsolHmMUyVY3dLWaoy+0ccJ5uf2QjA==", - "dev": true, - "dependencies": { - "comment-parser": "1.3.1", - "esquery": "^1.4.0", - "jsdoc-type-pratt-parser": "~3.1.0" - }, - "engines": { - "node": "^14 || ^16 || ^17 || ^18 || ^19" - } - }, "node_modules/@esbuild/android-arm": { "version": "0.15.13", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.13.tgz", @@ -1167,15 +1152,6 @@ "node": ">=8" } }, - "node_modules/comment-parser": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.1.tgz", - "integrity": "sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==", - "dev": true, - "engines": { - "node": ">= 12.0.0" - } - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1963,27 +1939,6 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, - "node_modules/eslint-plugin-jsdoc": { - "version": "39.6.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.6.2.tgz", - "integrity": "sha512-dvgY/W7eUFoAIIiaWHERIMI61ZWqcz9YFjEeyTzdPlrZc3TY/3aZm5aB91NUoTLWYZmO/vFlYSuQi15tF7uE5A==", - "dev": true, - "dependencies": { - "@es-joy/jsdoccomment": "~0.36.0", - "comment-parser": "1.3.1", - "debug": "^4.3.4", - "escape-string-regexp": "^4.0.0", - "esquery": "^1.4.0", - "semver": "^7.3.8", - "spdx-expression-parse": "^3.0.1" - }, - "engines": { - "node": "^14 || ^16 || ^17 || ^18 || ^19" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - } - }, "node_modules/eslint-plugin-local": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/eslint-plugin-local/-/eslint-plugin-local-1.0.0.tgz", @@ -3051,15 +3006,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsdoc-type-pratt-parser": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-3.1.0.tgz", - "integrity": "sha512-MgtD0ZiCDk9B+eI73BextfRrVQl0oyzRG8B2BjORts6jbunj4ScKPcyXGTbB6eXL4y9TzxCm6hyeLq/2ASzNdw==", - "dev": true, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -4010,28 +3956,6 @@ "source-map": "^0.6.0" } }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", - "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", - "dev": true - }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -4534,17 +4458,6 @@ } }, "dependencies": { - "@es-joy/jsdoccomment": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.36.0.tgz", - "integrity": "sha512-u0XZyvUF6Urb2cSivSXA8qXIpT/CxkHcdtZKoWusAzgzmsTWpg0F2FpWXsolHmMUyVY3dLWaoy+0ccJ5uf2QjA==", - "dev": true, - "requires": { - "comment-parser": "1.3.1", - "esquery": "^1.4.0", - "jsdoc-type-pratt-parser": "~3.1.0" - } - }, "@esbuild/android-arm": { "version": "0.15.13", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.13.tgz", @@ -5338,12 +5251,6 @@ } } }, - "comment-parser": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.1.tgz", - "integrity": "sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==", - "dev": true - }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -5870,21 +5777,6 @@ } } }, - "eslint-plugin-jsdoc": { - "version": "39.6.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.6.2.tgz", - "integrity": "sha512-dvgY/W7eUFoAIIiaWHERIMI61ZWqcz9YFjEeyTzdPlrZc3TY/3aZm5aB91NUoTLWYZmO/vFlYSuQi15tF7uE5A==", - "dev": true, - "requires": { - "@es-joy/jsdoccomment": "~0.36.0", - "comment-parser": "1.3.1", - "debug": "^4.3.4", - "escape-string-regexp": "^4.0.0", - "esquery": "^1.4.0", - "semver": "^7.3.8", - "spdx-expression-parse": "^3.0.1" - } - }, "eslint-plugin-local": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/eslint-plugin-local/-/eslint-plugin-local-1.0.0.tgz", @@ -6625,12 +6517,6 @@ "argparse": "^2.0.1" } }, - "jsdoc-type-pratt-parser": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-3.1.0.tgz", - "integrity": "sha512-MgtD0ZiCDk9B+eI73BextfRrVQl0oyzRG8B2BjORts6jbunj4ScKPcyXGTbB6eXL4y9TzxCm6hyeLq/2ASzNdw==", - "dev": true - }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -7288,28 +7174,6 @@ "source-map": "^0.6.0" } }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", - "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", - "dev": true - }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", diff --git a/package.json b/package.json index 671944ad1e6..b2e6200b3b9 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,6 @@ "eslint": "^8.22.0", "eslint-formatter-autolinkable-stylish": "^1.2.0", "eslint-plugin-import": "^2.26.0", - "eslint-plugin-jsdoc": "^39.3.6", "eslint-plugin-local": "^1.0.0", "eslint-plugin-no-null": "^1.0.2", "fast-xml-parser": "^4.0.11", diff --git a/scripts/eslint/rules/jsdoc-format.cjs b/scripts/eslint/rules/jsdoc-format.cjs index 86783b3547a..fe4bf64fb96 100644 --- a/scripts/eslint/rules/jsdoc-format.cjs +++ b/scripts/eslint/rules/jsdoc-format.cjs @@ -13,9 +13,11 @@ module.exports = createRule({ internalCommentNotLastError: `@internal should only appear in final JSDoc comment for declaration.`, multipleJSDocError: `Declaration has multiple JSDoc comments.`, internalCommentOnParameterProperty: `@internal cannot appear on a JSDoc comment; use a declared property and an assignment in the constructor instead.`, + misalignedJSDocComment: `This JSDoc comment is misaligned.`, }, schema: [], type: "problem", + fixable: "whitespace", }, defaultOptions: [], @@ -24,6 +26,11 @@ module.exports = createRule({ const atInternal = "@internal"; const jsdocStart = "/**"; + /** @type {(text: string) => boolean} */ + function isJSDocText(text) { + return text.startsWith(jsdocStart); + } + /** @type {(c: TSESTree.Comment, indexInComment: number) => TSESTree.SourceLocation} */ const getAtInternalLoc = (c, indexInComment) => { const line = c.loc.start.line; @@ -51,7 +58,7 @@ module.exports = createRule({ }; /** @type {(node: TSESTree.Node) => void} */ - const checkJSDocFormat = (node) => { + const checkDeclaration = (node) => { const blockComments = sourceCode.getCommentsBefore(node).filter(c => c.type === "Block"); if (blockComments.length === 0) { return; @@ -63,7 +70,7 @@ module.exports = createRule({ const c = blockComments[i]; const rawComment = sourceCode.getText(c); - const isJSDoc = rawComment.startsWith(jsdocStart); + const isJSDoc = isJSDocText(rawComment); if (isJSDoc && seenJSDoc) { context.report({ messageId: "multipleJSDocError", node: c, loc: getJSDocStartLoc(c) }); } @@ -86,25 +93,85 @@ module.exports = createRule({ } }; + /** @type {(node: TSESTree.Node) => void} */ + const checkProgram = () => { + const comments = sourceCode.getAllComments(); + + for (const c of comments) { + if (c.type !== "Block") { + continue; + } + + const rawComment = sourceCode.getText(c); + if (!isJSDocText(rawComment)) { + continue; + } + + const expected = c.loc.start.column + 2; + const split = rawComment.split(/\r?\n/g); + for (let i = 1; i < split.length; i++) { + const line = split[i]; + const match = /^ *\*/.exec(line); + if (!match) { + continue; + } + + const actual = match[0].length; + const diff = actual - expected; + if (diff !== 0) { + const line = c.loc.start.line + i; + context.report({ + messageId: "misalignedJSDocComment", + node: c, + loc: { + start: { + line, + column: 0, + }, + end: { + line, + column: actual - 1, + } + }, + fix: (fixer) => { + if (diff > 0) { + // Too many + const start = sourceCode.getIndexFromLoc({ line, column: expected - 1 }); + return fixer.removeRange([start, start + diff]); + } + else { + // Too few + const start = sourceCode.getIndexFromLoc({ line, column: 0 }); + return fixer.insertTextAfterRange([start, start], " ".repeat(-diff)); + } + }, + }); + break; + } + } + } + }; + return { - ClassDeclaration: checkJSDocFormat, - FunctionDeclaration: checkJSDocFormat, - TSEnumDeclaration: checkJSDocFormat, - TSModuleDeclaration: checkJSDocFormat, - VariableDeclaration: checkJSDocFormat, - TSInterfaceDeclaration: checkJSDocFormat, - TSTypeAliasDeclaration: checkJSDocFormat, - TSCallSignatureDeclaration: checkJSDocFormat, - ExportAllDeclaration: checkJSDocFormat, - ExportNamedDeclaration: checkJSDocFormat, - TSImportEqualsDeclaration: checkJSDocFormat, - TSNamespaceExportDeclaration: checkJSDocFormat, - TSConstructSignatureDeclaration: checkJSDocFormat, - ExportDefaultDeclaration: checkJSDocFormat, - TSPropertySignature: checkJSDocFormat, - TSIndexSignature: checkJSDocFormat, - TSMethodSignature: checkJSDocFormat, - TSParameterProperty: checkJSDocFormat, + Program: checkProgram, + ClassDeclaration: checkDeclaration, + FunctionDeclaration: checkDeclaration, + TSEnumDeclaration: checkDeclaration, + TSModuleDeclaration: checkDeclaration, + VariableDeclaration: checkDeclaration, + TSInterfaceDeclaration: checkDeclaration, + TSTypeAliasDeclaration: checkDeclaration, + TSCallSignatureDeclaration: checkDeclaration, + ExportAllDeclaration: checkDeclaration, + ExportNamedDeclaration: checkDeclaration, + TSImportEqualsDeclaration: checkDeclaration, + TSNamespaceExportDeclaration: checkDeclaration, + TSConstructSignatureDeclaration: checkDeclaration, + ExportDefaultDeclaration: checkDeclaration, + TSPropertySignature: checkDeclaration, + TSIndexSignature: checkDeclaration, + TSMethodSignature: checkDeclaration, + TSParameterProperty: checkDeclaration, }; }, }); From 1b35985f4fd962747139be0c95f4f06987e41c87 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Tue, 8 Nov 2022 15:20:22 -0800 Subject: [PATCH 03/11] Fix --bundle=false on Windows (#51459) --- Herebyfile.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Herebyfile.mjs b/Herebyfile.mjs index c58d330b624..b143a99d3af 100644 --- a/Herebyfile.mjs +++ b/Herebyfile.mjs @@ -320,7 +320,7 @@ function entrypointBuildTask(options) { const outDir = path.dirname(options.output); await fs.promises.mkdir(outDir, { recursive: true }); const moduleSpecifier = path.relative(outDir, options.builtEntrypoint); - await fs.promises.writeFile(options.output, `module.exports = require("./${moduleSpecifier}")`); + await fs.promises.writeFile(options.output, `module.exports = require("./${moduleSpecifier.replace(/[\\/]/g, "/")}")`); }, }); From d237468cdaf39423e4c14e11a8755bdaefb7d351 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Tue, 8 Nov 2022 15:39:04 -0800 Subject: [PATCH 04/11] Add --no-typecheck option for runtests/runtests-parallel/min/local (#51460) --- Herebyfile.mjs | 23 +++++++++++++++++------ scripts/build/options.mjs | 6 ++++-- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/Herebyfile.mjs b/Herebyfile.mjs index b143a99d3af..18a0483e837 100644 --- a/Herebyfile.mjs +++ b/Herebyfile.mjs @@ -354,7 +354,7 @@ function entrypointBuildTask(options) { } -const { main: tsc, watch: watchTsc } = entrypointBuildTask({ +const { main: tsc, build: buildTsc, watch: watchTsc } = entrypointBuildTask({ name: "tsc", description: "Builds the command-line compiler", buildDeps: [generateDiagnostics], @@ -392,7 +392,7 @@ export const dtsServices = task({ }); -const { main: tsserver, watch: watchTsserver } = entrypointBuildTask({ +const { main: tsserver, build: buildTsserver, watch: watchTsserver } = entrypointBuildTask({ name: "tsserver", description: "Builds the language server", buildDeps: [generateDiagnostics], @@ -410,10 +410,15 @@ const { main: tsserver, watch: watchTsserver } = entrypointBuildTask({ export { tsserver, watchTsserver }; +const buildMin = task({ + name: "build-min", + dependencies: [buildTsc, buildTsserver], +}); + export const min = task({ name: "min", description: "Builds only tsc and tsserver", - dependencies: [tsc, tsserver], + dependencies: [tsc, tsserver].concat(cmdLineOptions.typecheck ? [buildMin] : []), }); export const watchMin = task({ @@ -577,10 +582,15 @@ export const watchOtherOutputs = task({ dependencies: [watchCancellationToken, watchTypingsInstaller, watchWatchGuard, generateTypesMap, copyBuiltLocalDiagnosticMessages], }); +const buildLocal = task({ + name: "build-local", + dependencies: [buildTsc, buildTsserver, buildServices, buildLssl] +}); + export const local = task({ name: "local", description: "Builds the full compiler and services", - dependencies: [localize, tsc, tsserver, services, lssl, otherOutputs, dts, buildSrc], + dependencies: [localize, tsc, tsserver, services, lssl, otherOutputs, dts].concat(cmdLineOptions.typecheck ? [buildLocal] : []), }); export default local; @@ -591,11 +601,12 @@ export const watchLocal = task({ dependencies: [localize, watchTsc, watchTsserver, watchServices, watchLssl, watchOtherOutputs, dts, watchSrc], }); +const runtestsDeps = [tests, generateLibs].concat(cmdLineOptions.typecheck ? [dts, buildSrc] : []); export const runTests = task({ name: "runtests", description: "Runs the tests using the built run.js file.", - dependencies: [tests, generateLibs, dts, buildSrc], + dependencies: runtestsDeps, run: () => runConsoleTests(testRunner, "mocha-fivemat-progress-reporter", /*runInParallel*/ false), }); // task("runtests").flags = { @@ -617,7 +628,7 @@ export const runTests = task({ export const runTestsParallel = task({ name: "runtests-parallel", description: "Runs all the tests in parallel using the built run.js file.", - dependencies: [tests, generateLibs, dts, buildSrc], + dependencies: runtestsDeps, run: () => runConsoleTests(testRunner, "min", /*runInParallel*/ cmdLineOptions.workers > 1), }); // task("runtests-parallel").flags = { diff --git a/scripts/build/options.mjs b/scripts/build/options.mjs index 314d9f68026..38816afe509 100644 --- a/scripts/build/options.mjs +++ b/scripts/build/options.mjs @@ -4,7 +4,7 @@ import os from "os"; const ci = ["1", "true"].includes(process.env.CI ?? ""); const parsed = minimist(process.argv.slice(2), { - boolean: ["dirty", "light", "colors", "lkg", "soft", "fix", "failed", "keepFailed", "force", "built", "ci", "bundle"], + boolean: ["dirty", "light", "colors", "lkg", "soft", "fix", "failed", "keepFailed", "force", "built", "ci", "bundle", "typecheck"], string: ["browser", "tests", "break", "host", "reporter", "stackTraceLimit", "timeout", "shards", "shardId"], alias: { /* eslint-disable quote-props */ @@ -39,7 +39,8 @@ const parsed = minimist(process.argv.slice(2), { dirty: false, built: false, ci, - bundle: true + bundle: true, + typecheck: true, } }); @@ -80,5 +81,6 @@ export default options; * @property {string} shardId * @property {string} break * @property {boolean} bundle + * @property {boolean} typecheck */ void 0; From 0993c017bace34cbcbf8a19b830b22db95676ca4 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Tue, 8 Nov 2022 16:35:10 -0800 Subject: [PATCH 05/11] Fix JSDoc eslint rule for properties and methods (#51462) --- scripts/eslint/rules/jsdoc-format.cjs | 2 + src/server/editorServices.ts | 41 +++++++++++------ src/server/project.ts | 44 +++++++++++++------ src/server/scriptInfo.ts | 7 ++- .../reference/api/tsserverlibrary.d.ts | 2 - 5 files changed, 65 insertions(+), 31 deletions(-) diff --git a/scripts/eslint/rules/jsdoc-format.cjs b/scripts/eslint/rules/jsdoc-format.cjs index fe4bf64fb96..d8d78b97970 100644 --- a/scripts/eslint/rules/jsdoc-format.cjs +++ b/scripts/eslint/rules/jsdoc-format.cjs @@ -172,6 +172,8 @@ module.exports = createRule({ TSIndexSignature: checkDeclaration, TSMethodSignature: checkDeclaration, TSParameterProperty: checkDeclaration, + PropertyDefinition: checkDeclaration, + MethodDefinition: checkDeclaration, }; }, }); diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index b3e91f685ef..cad89c3a351 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -718,8 +718,9 @@ export class ProjectService { /** * Container of all known scripts + * + * @internal */ - /** @internal */ readonly filenameToScriptInfo = new Map(); private readonly nodeModulesWatchers = new Map(); /** @@ -733,8 +734,9 @@ export class ProjectService { /** * Map to the real path of the infos + * + * @internal */ - /** @internal */ readonly realpathToScriptInfos: MultiMap | undefined; /** * maps external project file name to list of config files that were the part of this project @@ -786,8 +788,11 @@ export class ProjectService { * In this case the exists could be true/false based on config file is present or not * - Or it is present if we have configured project open with config file at that location * In this case the exists property is always true + * + * + * @internal */ - /** @internal */ readonly configFileExistenceInfoCache = new Map(); + readonly configFileExistenceInfoCache = new Map(); /** @internal */ readonly throttledOperations: ThrottledOperations; private readonly hostConfiguration: HostConfiguration; @@ -1344,8 +1349,9 @@ export class ProjectService { /** * This is to watch whenever files are added or removed to the wildcard directories + * + * @internal */ - /** @internal */ private watchWildcardDirectory(directory: Path, flags: WatchDirectoryFlags, configFileName: NormalizedPath, config: ParsedConfig) { return this.watchFactory.watchDirectory( directory, @@ -1774,8 +1780,9 @@ export class ProjectService { /** * Close the config file watcher in the cached ConfigFileExistenceInfo * if there arent any open files that are root of inferred project and there is no parsed config held by any project + * + * @internal */ - /** @internal */ private closeConfigFileWatcherOnReleaseOfOpenFile(configFileExistenceInfo: ConfigFileExistenceInfo) { // Close the config file watcher if there are no more open files that are root of inferred project // or if there are no projects that need to watch this config file existence info @@ -1822,8 +1829,9 @@ export class ProjectService { /** * This is called by inferred project whenever script info is added as a root + * + * @internal */ - /** @internal */ startWatchingConfigFilesForInferredProjectRoot(info: ScriptInfo) { Debug.assert(info.isScriptOpen()); this.forEachConfigFileLocation(info, (canonicalConfigFilePath, configFileName) => { @@ -1852,8 +1860,9 @@ export class ProjectService { /** * This is called by inferred project whenever root script info is removed from it + * + * @internal */ - /** @internal */ stopWatchingConfigFilesForInferredProjectRoot(info: ScriptInfo) { this.forEachConfigFileLocation(info, canonicalConfigFilePath => { const configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath); @@ -2168,8 +2177,9 @@ export class ProjectService { /** * Read the config file of the project, and update the project root file names. + * + * @internal */ - /** @internal */ private loadConfiguredProject(project: ConfiguredProject, reason: string) { tracing?.push(tracing.Phase.Session, "loadConfiguredProject", { configFilePath: project.canonicalConfigFilePath }); this.sendProjectLoadingStartEvent(project, reason); @@ -2434,8 +2444,9 @@ export class ProjectService { /** * Reload the file names from config file specs and update the project graph + * + * @internal */ - /** @internal */ reloadFileNamesOfConfiguredProject(project: ConfiguredProject) { const fileNames = this.reloadFileNamesOfParsedConfig(project.getConfigFilePath(), this.configFileExistenceInfoCache.get(project.canonicalConfigFilePath)!.config!); project.updateErrorOnNoInputFiles(fileNames); @@ -2466,8 +2477,9 @@ export class ProjectService { /** * Read the config file of the project again by clearing the cache and update the project graph + * + * @internal */ - /** @internal */ reloadConfiguredProject(project: ConfiguredProject, reason: string, isInitialLoad: boolean, clearSemanticCache: boolean) { // At this point, there is no reason to not have configFile in the host const host = project.getCachedDirectoryStructureHost(); @@ -2632,8 +2644,9 @@ export class ProjectService { /** * Returns the projects that contain script info through SymLink * Note that this does not return projects in info.containingProjects + * + * @internal */ - /** @internal */ getSymlinkedProjects(info: ScriptInfo): MultiMap | undefined { let projects: MultiMap | undefined; if (this.realpathToScriptInfos) { @@ -4149,8 +4162,9 @@ export class ProjectService { /** * Waits for any ongoing plugin enablement requests to complete. + * + * @internal */ - /** @internal */ async waitForPendingPlugins() { while (this.currentPluginEnablementPromise) { await this.currentPluginEnablementPromise; @@ -4159,8 +4173,9 @@ export class ProjectService { /** * Starts enabling any requested plugins without waiting for the result. + * + * @internal */ - /** @internal */ enableRequestedPlugins() { if (this.pendingPluginEnablements) { void this.enableRequestedPluginsAsync(); diff --git a/src/server/project.ts b/src/server/project.ts index 64bd6a6c5c7..72a3064212d 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -175,14 +175,15 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo private missingFilesMap: ESMap | undefined; private generatedFilesMap: GeneratedFileWatcherMap | undefined; - /*@internal*/ + /** @internal */ protected readonly plugins: PluginModuleWithName[] = []; - /** @internal */ /** * This is map from files to unresolved imports in it * Maop does not contain entries for files that do not have unresolved imports * This helps in containing the set of files to invalidate + * + * @internal */ cachedUnresolvedImportsPerFile = new Map(); @@ -1642,7 +1643,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo return !!this.program && this.program.isSourceOfProjectReferenceRedirect(fileName); } - /*@internal*/ + /** @internal */ protected getGlobalPluginSearchPaths() { // Search any globally-specified probe paths, then our peer node_modules return [ @@ -1679,8 +1680,9 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo /** * Performs the initial steps of enabling a plugin by finding and instantiating the module for a plugin synchronously using 'require'. + * + * @internal */ - /** @internal */ beginEnablePluginSync(pluginConfigEntry: PluginImport, searchPaths: string[], pluginConfigOverrides: Map | undefined): BeginEnablePluginResult { Debug.assertIsDefined(this.projectService.host.require); @@ -1696,8 +1698,9 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo /** * Performs the initial steps of enabling a plugin by finding and instantiating the module for a plugin asynchronously using dynamic `import`. + * + * @internal */ - /** @internal */ async beginEnablePluginAsync(pluginConfigEntry: PluginImport, searchPaths: string[], pluginConfigOverrides: Map | undefined): Promise { Debug.assertIsDefined(this.projectService.host.importPlugin); @@ -1719,8 +1722,9 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo /** * Performs the remaining steps of enabling a plugin after its module has been instantiated. + * + * @internal */ - /** @internal */ endEnablePlugin({ pluginConfigEntry, pluginConfigOverrides, resolvedModule, errorLogs }: BeginEnablePluginResult) { if (resolvedModule) { const configurationOverride = pluginConfigOverrides && pluginConfigOverrides.get(pluginConfigEntry.name); @@ -2015,8 +2019,11 @@ export class InferredProject extends Project { /** this is canonical project root path */ readonly projectRootPath: string | undefined; - /** @internal */ - /** stored only if their is no projectRootPath and this isnt single inferred project */ + /** + * stored only if their is no projectRootPath and this isnt single inferred project + * + * @internal + */ readonly canonicalCurrentDirectory: string | undefined; /** @internal */ @@ -2412,8 +2419,11 @@ export class ConfiguredProject extends Project { private projectReferences: readonly ProjectReference[] | undefined; - /** Potential project references before the project is actually loaded (read config file) */ - /** @internal */ + /** + * Potential project references before the project is actually loaded (read config file) + * + * @internal + */ potentialProjectReferences: Set | undefined; /** @internal */ @@ -2630,8 +2640,11 @@ export class ConfiguredProject extends Project { !this.canConfigFileJsonReportNoInputFiles; } - /** @internal */ - /** Find the configured project from the project references in project which contains the info directly */ + /** + * Find the configured project from the project references in project which contains the info directly + * + * @internal + */ getDefaultChildProjectFromProjectWithReferences(info: ScriptInfo) { return forEachResolvedProjectReferenceProject( this, @@ -2643,8 +2656,11 @@ export class ConfiguredProject extends Project { ); } - /** Returns true if the project is needed by any of the open script info/external project */ - /** @internal */ + /** + * Returns true if the project is needed by any of the open script info/external project + * + * @internal + */ hasOpenRef() { if (!!this.externalProjectRefCount) { return true; diff --git a/src/server/scriptInfo.ts b/src/server/scriptInfo.ts index 25c77fe3d4d..4591bc07d71 100644 --- a/src/server/scriptInfo.ts +++ b/src/server/scriptInfo.ts @@ -317,8 +317,11 @@ export class ScriptInfo { /** @internal */ readonly isDynamic: boolean; - /** @internal */ - /** Set to real path if path is different from info.path */ + /** + * Set to real path if path is different from info.path + * + * @internal + */ private realpath: Path | undefined; /** @internal */ diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 6a93d33726e..c62807f4dbb 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -3127,7 +3127,6 @@ declare namespace ts { private externalFiles; private missingFilesMap; private generatedFilesMap; - protected readonly plugins: PluginModuleWithName[]; protected languageService: LanguageService; languageServiceEnabled: boolean; readonly trace?: (s: string) => void; @@ -3252,7 +3251,6 @@ declare namespace ts { setTypeAcquisition(newTypeAcquisition: TypeAcquisition | undefined): void; getTypeAcquisition(): ts.TypeAcquisition; protected removeRoot(info: ScriptInfo): void; - protected getGlobalPluginSearchPaths(): string[]; protected enableGlobalPlugins(options: CompilerOptions, pluginConfigOverrides: Map | undefined): void; protected enablePlugin(pluginConfigEntry: PluginImport, searchPaths: string[], pluginConfigOverrides: Map | undefined): void; private enableProxy; From 19091abda1b754abb418843128d937bc026bdd3a Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 9 Nov 2022 08:00:58 -0800 Subject: [PATCH 06/11] Fix missing awaits in Herebyfile (#51465) --- Herebyfile.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Herebyfile.mjs b/Herebyfile.mjs index 18a0483e837..9ae0279cc67 100644 --- a/Herebyfile.mjs +++ b/Herebyfile.mjs @@ -141,7 +141,7 @@ const localize = task({ dependencies: [generateDiagnostics], run: async () => { if (needsUpdate(diagnosticMessagesGeneratedJson, generatedLCGFile)) { - return exec(process.execPath, ["scripts/generateLocalizedDiagnosticMessages.mjs", "src/loc/lcl", "built/local", diagnosticMessagesGeneratedJson], { ignoreExitCode: true }); + await exec(process.execPath, ["scripts/generateLocalizedDiagnosticMessages.mjs", "src/loc/lcl", "built/local", diagnosticMessagesGeneratedJson], { ignoreExitCode: true }); } } }); @@ -386,7 +386,7 @@ export const dtsServices = task({ dependencies: [buildServices], run: async () => { if (needsUpdate("./built/local/typescript/tsconfig.tsbuildinfo", ["./built/local/typescript.d.ts", "./built/local/typescript.internal.d.ts"])) { - runDtsBundler("./built/local/typescript/typescript.d.ts", "./built/local/typescript.d.ts"); + await runDtsBundler("./built/local/typescript/typescript.d.ts", "./built/local/typescript.d.ts"); } }, }); From 6e0a62e8dd12c4ee8cb26be4431a6c096dc02889 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Wed, 9 Nov 2022 10:02:40 -0800 Subject: [PATCH 07/11] 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 --- src/harness/_namespaces/ts.TestFSWithWatch.ts | 3 - src/harness/_namespaces/ts.ts | 4 +- src/harness/vfsUtil.ts | 6 +- .../_namespaces/ts.projectSystem.ts | 3 - src/testRunner/_namespaces/ts.ts | 10 +- src/testRunner/_namespaces/ts.tscWatch.ts | 3 - src/testRunner/unittests/builder.ts | 39 +- .../unittests/config/projectReferences.ts | 3 +- src/testRunner/unittests/helpers.ts | 2 +- src/testRunner/unittests/moduleResolution.ts | 108 +- .../unittests/reuseProgramStructure.ts | 22 +- .../services/convertToAsyncFunction.ts | 21 +- .../unittests/services/extract/constants.ts | 5 +- .../unittests/services/extract/functions.ts | 3 +- .../unittests/services/extract/helpers.ts | 10 +- .../unittests/services/extract/ranges.ts | 5 +- .../unittests/services/languageService.ts | 55 +- .../unittests/services/organizeImports.ts | 17 +- .../unittests/services/textChanges.ts | 3 +- .../unittests/tsbuild/amdModulesWithOut.ts | 57 +- src/testRunner/unittests/tsbuild/clean.ts | 7 +- .../unittests/tsbuild/commandLine.ts | 135 +- .../unittests/tsbuild/configFileErrors.ts | 20 +- .../unittests/tsbuild/configFileExtends.ts | 8 +- .../tsbuild/containerOnlyReferenced.ts | 14 +- .../unittests/tsbuild/declarationEmit.ts | 14 +- src/testRunner/unittests/tsbuild/demo.ts | 14 +- .../unittests/tsbuild/emitDeclarationOnly.ts | 18 +- .../unittests/tsbuild/emptyFiles.ts | 8 +- .../unittests/tsbuild/exitCodeOnBogusFile.ts | 6 +- src/testRunner/unittests/tsbuild/helpers.ts | 769 ---------- .../inferredTypeFromTransitiveModule.ts | 20 +- .../tsbuild/javascriptProjectEmit.ts | 22 +- .../unittests/tsbuild/lateBoundSymbol.ts | 10 +- .../unittests/tsbuild/moduleResolution.ts | 41 +- .../unittests/tsbuild/moduleSpecifiers.ts | 15 +- src/testRunner/unittests/tsbuild/noEmit.ts | 10 +- .../unittests/tsbuild/noEmitOnError.ts | 28 +- src/testRunner/unittests/tsbuild/outFile.ts | 201 +-- .../unittests/tsbuild/outputPaths.ts | 23 +- src/testRunner/unittests/tsbuild/publicApi.ts | 15 +- .../tsbuild/referencesWithRootDirInParent.ts | 14 +- .../unittests/tsbuild/resolveJsonModule.ts | 32 +- src/testRunner/unittests/tsbuild/sample.ts | 156 +- .../unittests/tsbuild/transitiveReferences.ts | 10 +- .../tsbuildWatch/configFileErrors.ts | 31 +- src/testRunner/unittests/tsbuildWatch/demo.ts | 39 +- .../tsbuildWatch/moduleResolution.ts | 115 +- .../unittests/tsbuildWatch/noEmit.ts | 32 +- .../unittests/tsbuildWatch/noEmitOnError.ts | 32 +- .../unittests/tsbuildWatch/programUpdates.ts | 300 ++-- .../tsbuildWatch/projectsBuilding.ts | 120 +- .../unittests/tsbuildWatch/publicApi.ts | 28 +- .../unittests/tsbuildWatch/reexport.ts | 18 +- .../tsbuildWatch/watchEnvironment.ts | 28 +- .../unittests/tsc/cancellationToken.ts | 45 +- src/testRunner/unittests/tsc/composite.ts | 24 +- .../unittests/tsc/declarationEmit.ts | 88 +- .../tsc/forceConsistentCasingInFileNames.ts | 6 +- src/testRunner/unittests/tsc/helpers.ts | 798 ++++++++++- src/testRunner/unittests/tsc/incremental.ts | 207 +-- src/testRunner/unittests/tsc/listFilesOnly.ts | 20 +- .../unittests/tsc/projectReferences.ts | 10 +- src/testRunner/unittests/tsc/redirect.ts | 6 +- .../unittests/tsc/runWithoutArgs.ts | 14 +- .../unittests/tscWatch/consoleClearing.ts | 26 +- src/testRunner/unittests/tscWatch/emit.ts | 142 +- .../unittests/tscWatch/emitAndErrorUpdates.ts | 168 +-- .../forceConsistentCasingInFileNames.ts | 156 +- src/testRunner/unittests/tscWatch/helpers.ts | 231 +-- .../unittests/tscWatch/incremental.ts | 83 +- .../unittests/tscWatch/moduleResolution.ts | 146 +- .../unittests/tscWatch/nodeNextWatch.ts | 17 +- .../unittests/tscWatch/programUpdates.ts | 737 +++++----- .../tscWatch/projectsWithReferences.ts | 266 ++-- .../unittests/tscWatch/resolutionCache.ts | 170 +-- .../sourceOfProjectReferenceRedirect.ts | 64 +- src/testRunner/unittests/tscWatch/watchApi.ts | 245 ++-- .../unittests/tscWatch/watchEnvironment.ts | 285 ++-- .../tsserver/applyChangesToOpenFiles.ts | 81 +- .../unittests/tsserver/autoImportProvider.ts | 76 +- .../unittests/tsserver/auxiliaryProject.ts | 18 +- .../tsserver/cachingFileSystemInformation.ts | 148 +- .../unittests/tsserver/cancellationToken.ts | 56 +- .../unittests/tsserver/compileOnSave.ts | 391 ++--- .../unittests/tsserver/completions.ts | 82 +- .../tsserver/completionsIncomplete.ts | 96 +- .../unittests/tsserver/configFileSearch.ts | 55 +- .../unittests/tsserver/configuredProjects.ts | 589 ++++---- .../unittests/tsserver/declarationFileMaps.ts | 298 ++-- .../unittests/tsserver/documentRegistry.ts | 28 +- .../unittests/tsserver/duplicatePackages.ts | 26 +- .../unittests/tsserver/dynamicFiles.ts | 155 +- .../tsserver/events/largeFileReferenced.ts | 38 +- .../events/projectLanguageServiceState.ts | 26 +- .../tsserver/events/projectLoading.ts | 72 +- .../events/projectUpdatedInBackground.ts | 96 +- .../unittests/tsserver/exportMapCache.ts | 34 +- .../unittests/tsserver/externalProjects.ts | 348 ++--- .../forceConsistentCasingInFileNames.ts | 88 +- .../unittests/tsserver/formatSettings.ts | 6 +- .../tsserver/getApplicableRefactors.ts | 14 +- .../tsserver/getEditsForFileRename.ts | 60 +- .../unittests/tsserver/getExportReferences.ts | 64 +- .../unittests/tsserver/getFileReferences.ts | 46 +- src/testRunner/unittests/tsserver/helpers.ts | 99 +- .../unittests/tsserver/importHelpers.ts | 9 +- .../unittests/tsserver/inferredProjects.ts | 171 +-- .../unittests/tsserver/inlayHints.ts | 37 +- src/testRunner/unittests/tsserver/jsdocTag.ts | 86 +- .../unittests/tsserver/languageService.ts | 10 +- .../tsserver/maxNodeModuleJsDepth.ts | 16 +- .../unittests/tsserver/metadataInResponse.ts | 46 +- .../unittests/tsserver/moduleResolution.ts | 31 +- .../tsserver/moduleSpecifierCache.ts | 44 +- src/testRunner/unittests/tsserver/navTo.ts | 80 +- .../unittests/tsserver/occurences.ts | 26 +- src/testRunner/unittests/tsserver/openFile.ts | 76 +- .../unittests/tsserver/packageJsonInfo.ts | 14 +- .../tsserver/partialSemanticServer.ts | 156 +- src/testRunner/unittests/tsserver/plugins.ts | 46 +- .../unittests/tsserver/projectErrors.ts | 376 ++--- .../tsserver/projectReferenceCompileOnSave.ts | 1257 +++++++++-------- .../tsserver/projectReferenceErrors.ts | 33 +- .../unittests/tsserver/projectReferences.ts | 644 ++++----- .../tsserver/projectReferencesSourcemap.ts | 378 ++--- src/testRunner/unittests/tsserver/projects.ts | 689 ++++----- .../tsserver/projectsWithReferences.ts | 129 +- .../unittests/tsserver/refactors.ts | 24 +- src/testRunner/unittests/tsserver/reload.ts | 14 +- .../unittests/tsserver/reloadProjects.ts | 76 +- src/testRunner/unittests/tsserver/rename.ts | 120 +- .../unittests/tsserver/resolutionCache.ts | 286 ++-- src/testRunner/unittests/tsserver/session.ts | 9 +- .../unittests/tsserver/skipLibCheck.ts | 108 +- .../unittests/tsserver/smartSelection.ts | 16 +- src/testRunner/unittests/tsserver/symLinks.ts | 85 +- .../unittests/tsserver/symlinkCache.ts | 22 +- .../unittests/tsserver/syntacticServer.ts | 120 +- .../unittests/tsserver/syntaxOperations.ts | 54 +- .../unittests/tsserver/telemetry.ts | 48 +- .../unittests/tsserver/textStorage.ts | 18 +- .../unittests/tsserver/typeAquisition.ts | 14 +- .../tsserver/typeOnlyImportChains.ts | 16 +- .../tsserver/typeReferenceDirectives.ts | 41 +- .../unittests/tsserver/typingsInstaller.ts | 547 ++++--- .../unittests/tsserver/watchEnvironment.ts | 324 ++--- .../unittests/tsserver/webServer.ts | 42 +- .../unittests}/virtualFileSystemWithWatch.ts | 40 +- 149 files changed, 8114 insertions(+), 8040 deletions(-) delete mode 100644 src/harness/_namespaces/ts.TestFSWithWatch.ts delete mode 100644 src/testRunner/_namespaces/ts.projectSystem.ts delete mode 100644 src/testRunner/_namespaces/ts.tscWatch.ts delete mode 100644 src/testRunner/unittests/tsbuild/helpers.ts rename src/{harness => testRunner/unittests}/virtualFileSystemWithWatch.ts (94%) diff --git a/src/harness/_namespaces/ts.TestFSWithWatch.ts b/src/harness/_namespaces/ts.TestFSWithWatch.ts deleted file mode 100644 index d20826a03b0..00000000000 --- a/src/harness/_namespaces/ts.TestFSWithWatch.ts +++ /dev/null @@ -1,3 +0,0 @@ -/* Generated file to emulate the ts.TestFSWithWatch namespace. */ - -export * from "../virtualFileSystemWithWatch"; diff --git a/src/harness/_namespaces/ts.ts b/src/harness/_namespaces/ts.ts index 9c29cb29056..6f90664e41e 100644 --- a/src/harness/_namespaces/ts.ts +++ b/src/harness/_namespaces/ts.ts @@ -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 }; \ No newline at end of file diff --git a/src/harness/vfsUtil.ts b/src/harness/vfsUtil.ts index b52f712e768..764b2fa63d0 100644 --- a/src/harness/vfsUtil.ts +++ b/src/harness/vfsUtil.ts @@ -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; } diff --git a/src/testRunner/_namespaces/ts.projectSystem.ts b/src/testRunner/_namespaces/ts.projectSystem.ts deleted file mode 100644 index 2723fee96d7..00000000000 --- a/src/testRunner/_namespaces/ts.projectSystem.ts +++ /dev/null @@ -1,3 +0,0 @@ -/* Generated file to emulate the ts.projectSystem namespace. */ - -export * from "../unittests/tsserver/helpers"; diff --git a/src/testRunner/_namespaces/ts.ts b/src/testRunner/_namespaces/ts.ts index d763d9b8291..427c6e4e071 100644 --- a/src/testRunner/_namespaces/ts.ts +++ b/src/testRunner/_namespaces/ts.ts @@ -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 }; \ No newline at end of file diff --git a/src/testRunner/_namespaces/ts.tscWatch.ts b/src/testRunner/_namespaces/ts.tscWatch.ts deleted file mode 100644 index aaa9390cb9e..00000000000 --- a/src/testRunner/_namespaces/ts.tscWatch.ts +++ /dev/null @@ -1,3 +0,0 @@ -/* Generated file to emulate the ts.tscWatch namespace. */ - -export * from "../unittests/tscWatch/helpers"; diff --git a/src/testRunner/unittests/builder.ts b/src/testRunner/unittests/builder.ts index 6494c6f3bed..0c3a8535a9d 100644 --- a/src/testRunner/unittests/builder.ts +++ b/src/testRunner/unittests/builder.ts @@ -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); }); } diff --git a/src/testRunner/unittests/config/projectReferences.ts b/src/testRunner/unittests/config/projectReferences.ts index e45fbb59abd..f8b93030262 100644 --- a/src/testRunner/unittests/config/projectReferences.ts +++ b/src/testRunner/unittests/config/projectReferences.ts @@ -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); diff --git a/src/testRunner/unittests/helpers.ts b/src/testRunner/unittests/helpers.ts index 7706b16ab1a..b4a1bee8c08 100644 --- a/src/testRunner/unittests/helpers.ts +++ b/src/testRunner/unittests/helpers.ts @@ -204,7 +204,7 @@ function mapEqualToCache(left: ts.ESMap, right: ts.ModeAwareCache< } export function checkResolvedModulesCache(program: ts.Program, fileName: string, expectedContent: ts.ESMap | 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 | undefined): void { diff --git a/src/testRunner/unittests/moduleResolution.ts b/src/testRunner/unittests/moduleResolution.ts index 7f2c76fedd3..f16adab4455 100644 --- a/src/testRunner/unittests/moduleResolution.ts +++ b/src/testRunner/unittests/moduleResolution.ts @@ -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(); 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", `/// `.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"`), diff --git a/src/testRunner/unittests/reuseProgramStructure.ts b/src/testRunner/unittests/reuseProgramStructure.ts index 95daa58cef6..0150cc976c6 100644 --- a/src/testRunner/unittests/reuseProgramStructure.ts +++ b/src/testRunner/unittests/reuseProgramStructure.ts @@ -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, diff --git a/src/testRunner/unittests/services/convertToAsyncFunction.ts b/src/testRunner/unittests/services/convertToAsyncFunction.ts index 0df0a9691cc..dd5543cbac2 100644 --- a/src/testRunner/unittests/services/convertToAsyncFunction.ts +++ b/src/testRunner/unittests/services/convertToAsyncFunction.ts @@ -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: `/// interface Boolean {} @@ -264,7 +267,7 @@ interface String { charAt: any; } interface Array {}` }; -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(); } diff --git a/src/testRunner/unittests/services/extract/constants.ts b/src/testRunner/unittests/services/extract/constants.ts index 55a30e21b83..b99760b97a2 100644 --- a/src/testRunner/unittests/services/extract/constants.ts +++ b/src/testRunner/unittests/services/extract/constants.ts @@ -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); } diff --git a/src/testRunner/unittests/services/extract/functions.ts b/src/testRunner/unittests/services/extract/functions.ts index 06f2943970e..0405a55c1f3 100644 --- a/src/testRunner/unittests/services/extract/functions.ts +++ b/src/testRunner/unittests/services/extract/functions.ts @@ -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); } diff --git a/src/testRunner/unittests/services/extract/helpers.ts b/src/testRunner/unittests/services/extract/helpers.ts index 959b8447c73..26a0e855136 100644 --- a/src/testRunner/unittests/services/extract/helpers.ts +++ b/src/testRunner/unittests/services/extract/helpers.ts @@ -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)!; diff --git a/src/testRunner/unittests/services/extract/ranges.ts b/src/testRunner/unittests/services/extract/ranges.ts index 71d35599130..e93be12fe11 100644 --- a/src/testRunner/unittests/services/extract/ranges.ts +++ b/src/testRunner/unittests/services/extract/ranges.ts @@ -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) { diff --git a/src/testRunner/unittests/services/languageService.ts b/src/testRunner/unittests/services/languageService.ts index 27b75cadfe4..b5d5b8101c6 100644 --- a/src/testRunner/unittests/services/languageService.ts +++ b/src/testRunner/unittests/services/languageService.ts @@ -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(); 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] ); }); }); diff --git a/src/testRunner/unittests/services/organizeImports.ts b/src/testRunner/unittests/services/organizeImports.ts index 05fcabe6622..59f1d9a9cae 100644 --- a/src/testRunner/unittests/services/organizeImports.ts +++ b/src/testRunner/unittests/services/organizeImports.ts @@ -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(); diff --git a/src/testRunner/unittests/services/textChanges.ts b/src/testRunner/unittests/services/textChanges.ts index 9c47393c819..a7610831459 100644 --- a/src/testRunner/unittests/services/textChanges.ts +++ b/src/testRunner/unittests/services/textChanges.ts @@ -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. diff --git a/src/testRunner/unittests/tsbuild/amdModulesWithOut.ts b/src/testRunner/unittests/tsbuild/amdModulesWithOut.ts index d137e70ecc4..a835b87109d 100644 --- a/src/testRunner/unittests/tsbuild/amdModulesWithOut.ts +++ b/src/testRunner/unittests/tsbuild/amdModulesWithOut.ts @@ -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, diff --git a/src/testRunner/unittests/tsbuild/clean.ts b/src/testRunner/unittests/tsbuild/clean.ts index c3182026a19..48fc319eabd 100644 --- a/src/testRunner/unittests/tsbuild/clean.ts +++ b/src/testRunner/unittests/tsbuild/clean.ts @@ -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({ diff --git a/src/testRunner/unittests/tsbuild/commandLine.ts b/src/testRunner/unittests/tsbuild/commandLine.ts index 4fe827ff86d..dfd703445ee 100644 --- a/src/testRunner/unittests/tsbuild/commandLine.ts +++ b/src/testRunner/unittests/tsbuild/commandLine.ts @@ -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"], }, ], diff --git a/src/testRunner/unittests/tsbuild/configFileErrors.ts b/src/testRunner/unittests/tsbuild/configFileErrors.ts index 7ed7ad9b8a9..f1d047c37c5 100644 --- a/src/testRunner/unittests/tsbuild/configFileErrors.ts +++ b/src/testRunner/unittests/tsbuild/configFileErrors.ts @@ -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", diff --git a/src/testRunner/unittests/tsbuild/configFileExtends.ts b/src/testRunner/unittests/tsbuild/configFileExtends.ts index 85d868dc063..c319b10f86e 100644 --- a/src/testRunner/unittests/tsbuild/configFileExtends.ts +++ b/src/testRunner/unittests/tsbuild/configFileExtends.ts @@ -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, diff --git a/src/testRunner/unittests/tsbuild/containerOnlyReferenced.ts b/src/testRunner/unittests/tsbuild/containerOnlyReferenced.ts index 45e4be83806..ed0a50da8a0 100644 --- a/src/testRunner/unittests/tsbuild/containerOnlyReferenced.ts +++ b/src/testRunner/unittests/tsbuild/containerOnlyReferenced.ts @@ -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 = "), }], }); }); diff --git a/src/testRunner/unittests/tsbuild/declarationEmit.ts b/src/testRunner/unittests/tsbuild/declarationEmit.ts index e7dc2b9f507..f819b1f55c9 100644 --- a/src/testRunner/unittests/tsbuild/declarationEmit.ts +++ b/src/testRunner/unittests/tsbuild/declarationEmit.ts @@ -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 & { };`, }; } - 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 & { 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, diff --git a/src/testRunner/unittests/tsbuild/demo.ts b/src/testRunner/unittests/tsbuild/demo.ts index 18666a748df..371cae4b63f 100644 --- a/src/testRunner/unittests/tsbuild/demo.ts +++ b/src/testRunner/unittests/tsbuild/demo.ts @@ -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'; diff --git a/src/testRunner/unittests/tsbuild/emitDeclarationOnly.ts b/src/testRunner/unittests/tsbuild/emitDeclarationOnly.ts index f7726fa3499..2c35740fa39 100644 --- a/src/testRunner/unittests/tsbuild/emitDeclarationOnly.ts +++ b/src/testRunner/unittests/tsbuild/emitDeclarationOnly.ts @@ -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;"), }, ], }); diff --git a/src/testRunner/unittests/tsbuild/emptyFiles.ts b/src/testRunner/unittests/tsbuild/emptyFiles.ts index 49d18ace609..72430346781 100644 --- a/src/testRunner/unittests/tsbuild/emptyFiles.ts +++ b/src/testRunner/unittests/tsbuild/emptyFiles.ts @@ -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, diff --git a/src/testRunner/unittests/tsbuild/exitCodeOnBogusFile.ts b/src/testRunner/unittests/tsbuild/exitCodeOnBogusFile.ts index f75d4a191d9..6e8aff6c2af 100644 --- a/src/testRunner/unittests/tsbuild/exitCodeOnBogusFile.ts +++ b/src/testRunner/unittests/tsbuild/exitCodeOnBogusFile.ts @@ -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"] }); }); diff --git a/src/testRunner/unittests/tsbuild/helpers.ts b/src/testRunner/unittests/tsbuild/helpers.ts deleted file mode 100644 index 09f38eecd9f..00000000000 --- a/src/testRunner/unittests/tsbuild/helpers.ts +++ /dev/null @@ -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 {} -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; }) { - 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 = Omit & { - impliedFormat: string | undefined; - original: T | undefined; -}; -type ReadableProgramMultiFileEmitBuildInfo = Omit & { - fileNamesList: readonly (readonly string[])[] | undefined; - fileInfos: ts.MapLike>; - referencedMap: ts.MapLike | undefined; - exportedModulesMap: ts.MapLike | 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 & { - fileInfos: ts.MapLike>; - pendingEmit: ReadableProgramBuildInfoBundlePendingEmit | undefined; -}; - -type ReadableProgramBuildInfo = ReadableProgramMultiFileEmitBuildInfo | ReadableProgramBundleEmitBuildInfo; - -function isReadableProgramBundleEmitBuildInfo(info: ReadableProgramBuildInfo | undefined): info is ReadableProgramBundleEmitBuildInfo { - return !!info && !!ts.outFile(info.options || {}); -} -type ReadableBuildInfo = Omit & { 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(original: T, toFileInfo: (fileInfo: T) => ts.BuilderState.FileInfo): ReadableProgramBuildInfoFileInfo { - 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 | undefined { - if (!referenceMap) return undefined; - const result: ts.MapLike = {}; - 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(incremental: ts.MapLike | undefined, clean: ts.MapLike | 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(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(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 | ReadableProgramBuildInfoFileInfo, "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`, `/// -const ${file}Const = new ${project}${file}(); -`); -} diff --git a/src/testRunner/unittests/tsbuild/inferredTypeFromTransitiveModule.ts b/src/testRunner/unittests/tsbuild/inferredTypeFromTransitiveModule.ts index 4f3db7518f6..1933a979dcf 100644 --- a/src/testRunner/unittests/tsbuild/inferredTypeFromTransitiveModule.ts +++ b/src/testRunner/unittests/tsbuild/inferredTypeFromTransitiveModule.ts @@ -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)"); } diff --git a/src/testRunner/unittests/tsbuild/javascriptProjectEmit.ts b/src/testRunner/unittests/tsbuild/javascriptProjectEmit.ts index 499ca98a604..744cc88faa6 100644 --- a/src/testRunner/unittests/tsbuild/javascriptProjectEmit.ts +++ b/src/testRunner/unittests/tsbuild/javascriptProjectEmit.ts @@ -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"] }); }); diff --git a/src/testRunner/unittests/tsbuild/lateBoundSymbol.ts b/src/testRunner/unittests/tsbuild/lateBoundSymbol.ts index 417be59e441..161a6063a86 100644 --- a/src/testRunner/unittests/tsbuild/lateBoundSymbol.ts +++ b/src/testRunner/unittests/tsbuild/lateBoundSymbol.ts @@ -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;"), }, ] }); diff --git a/src/testRunner/unittests/tsbuild/moduleResolution.ts b/src/testRunner/unittests/tsbuild/moduleResolution.ts index 496131f2c45..cb095a477d8 100644 --- a/src/testRunner/unittests/tsbuild/moduleResolution.ts +++ b/src/testRunner/unittests/tsbuild/moduleResolution.ts @@ -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 }); }); \ No newline at end of file diff --git a/src/testRunner/unittests/tsbuild/moduleSpecifiers.ts b/src/testRunner/unittests/tsbuild/moduleSpecifiers.ts index 04d3f714a6c..d8023f071b1 100644 --- a/src/testRunner/unittests/tsbuild/moduleSpecifiers.ts +++ b/src/testRunner/unittests/tsbuild/moduleSpecifiers.ts @@ -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 & { [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"); }, diff --git a/src/testRunner/unittests/tsbuild/noEmit.ts b/src/testRunner/unittests/tsbuild/noEmit.ts index 19cb8a50496..0782691f47c 100644 --- a/src/testRunner/unittests/tsbuild/noEmit.ts +++ b/src/testRunner/unittests/tsbuild/noEmit.ts @@ -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, }); diff --git a/src/testRunner/unittests/tsbuild/noEmitOnError.ts b/src/testRunner/unittests/tsbuild/noEmitOnError.ts index c61f45a1cd8..a5bdfc3b5c7 100644 --- a/src/testRunner/unittests/tsbuild/noEmitOnError.ts +++ b/src/testRunner/unittests/tsbuild/noEmitOnError.ts @@ -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, }); diff --git a/src/testRunner/unittests/tsbuild/outFile.ts b/src/testRunner/unittests/tsbuild/outFile.ts index 08a80e200ec..e0a9ac5bad9 100644 --- a/src/testRunner/unittests/tsbuild/outFile.ts +++ b/src/testRunner/unittests/tsbuild/outFile.ts @@ -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",`, ""); }, }); }); diff --git a/src/testRunner/unittests/tsbuild/outputPaths.ts b/src/testRunner/unittests/tsbuild/outputPaths.ts index 08f24dfcf60..a58f3d43808 100644 --- a/src/testRunner/unittests/tsbuild/outputPaths.ts +++ b/src/testRunner/unittests/tsbuild/outputPaths.ts @@ -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, expectedOuptutNames: readonly string[]) { - ts.verifyTscWithEdits({ + function verify(input: Pick, 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({ diff --git a/src/testRunner/unittests/tsbuild/publicApi.ts b/src/testRunner/unittests/tsbuild/publicApi.ts index b61ba2f5d89..c303262d298 100644 --- a/src/testRunner/unittests/tsbuild/publicApi.ts +++ b/src/testRunner/unittests/tsbuild/publicApi.ts @@ -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); }); diff --git a/src/testRunner/unittests/tsbuild/referencesWithRootDirInParent.ts b/src/testRunner/unittests/tsbuild/referencesWithRootDirInParent.ts index 1d0d2f131a2..4349e906559 100644 --- a/src/testRunner/unittests/tsbuild/referencesWithRootDirInParent.ts +++ b/src/testRunner/unittests/tsbuild/referencesWithRootDirInParent.ts @@ -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, diff --git a/src/testRunner/unittests/tsbuild/resolveJsonModule.ts b/src/testRunner/unittests/tsbuild/resolveJsonModule.ts index 0d765605c8f..27ef64a886f 100644 --- a/src/testRunner/unittests/tsbuild/resolveJsonModule.ts +++ b/src/testRunner/unittests/tsbuild/resolveJsonModule.ts @@ -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 }); }); diff --git a/src/testRunner/unittests/tsbuild/sample.ts b/src/testRunner/unittests/tsbuild/sample.ts index 60e8e7b7213..2fb4d2eee32 100644 --- a/src/testRunner/unittests/tsbuild/sample.ts +++ b/src/testRunner/unittests/tsbuild/sample.ts @@ -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 | undefined; - const system = ts.TestFSWithWatch.changeToHostTrackingWrittenFiles( + let oldSnap: ReturnType | 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 | undefined; - const system = ts.TestFSWithWatch.changeToHostTrackingWrittenFiles( + let oldSnap: ReturnType | 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", `/// /// `); - fs.writeFileSync("/lib/lib.esnext.d.ts", ts.libContent); + fs.writeFileSync("/lib/lib.esnext.d.ts", libContent); fs.writeFileSync("/lib/lib.d.ts", `/// /// `); 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, diff --git a/src/testRunner/unittests/tsbuild/transitiveReferences.ts b/src/testRunner/unittests/tsbuild/transitiveReferences.ts index c3374cb3703..b48a9c9c691 100644 --- a/src/testRunner/unittests/tsbuild/transitiveReferences.ts +++ b/src/testRunner/unittests/tsbuild/transitiveReferences.ts @@ -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, diff --git a/src/testRunner/unittests/tsbuildWatch/configFileErrors.ts b/src/testRunner/unittests/tsbuildWatch/configFileErrors.ts index 73e9fd0e5fb..cf4eda9a904 100644 --- a/src/testRunner/unittests/tsbuildWatch/configFileErrors.ts +++ b/src/testRunner/unittests/tsbuildWatch/configFileErrors.ts @@ -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"] })), diff --git a/src/testRunner/unittests/tsbuildWatch/demo.ts b/src/testRunner/unittests/tsbuildWatch/demo.ts index 81ab4dda2da..54aa361a76c 100644 --- a/src/testRunner/unittests/tsbuildWatch/demo.ts +++ b/src/testRunner/unittests/tsbuildWatch/demo.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); } }); \ No newline at end of file diff --git a/src/testRunner/unittests/tsbuildWatch/moduleResolution.ts b/src/testRunner/unittests/tsbuildWatch/moduleResolution.ts index 044ec4844aa..05889e33048 100644 --- a/src/testRunner/unittests/tsbuildWatch/moduleResolution.ts +++ b/src/testRunner/unittests/tsbuildWatch/moduleResolution.ts @@ -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(), }, ] }); diff --git a/src/testRunner/unittests/tsbuildWatch/noEmit.ts b/src/testRunner/unittests/tsbuildWatch/noEmit.ts index 37623cd14ae..b6d77b0cf8d 100644 --- a/src/testRunner/unittests/tsbuildWatch/noEmit.ts +++ b/src/testRunner/unittests/tsbuildWatch/noEmit.ts @@ -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 diff --git a/src/testRunner/unittests/tsbuildWatch/noEmitOnError.ts b/src/testRunner/unittests/tsbuildWatch/noEmitOnError.ts index c59bdc9d869..f9dfe11eba1 100644 --- a/src/testRunner/unittests/tsbuildWatch/noEmitOnError.ts +++ b/src/testRunner/unittests/tsbuildWatch/noEmitOnError.ts @@ -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, diff --git a/src/testRunner/unittests/tsbuildWatch/programUpdates.ts b/src/testRunner/unittests/tsbuildWatch/programUpdates.ts index 3d0e24d006c..f4147f4870d 100644 --- a/src/testRunner/unittests/tsbuildWatch/programUpdates.ts +++ b/src/testRunner/unittests/tsbuildWatch/programUpdates.ts @@ -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; + type ReadonlyFile = Readonly; /** [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 diff --git a/src/testRunner/unittests/tsbuildWatch/projectsBuilding.ts b/src/testRunner/unittests/tsbuildWatch/projectsBuilding.ts index b79c49a43b4..f95f91590af 100644 --- a/src/testRunner/unittests/tsbuildWatch/projectsBuilding.ts +++ b/src/testRunner/unittests/tsbuildWatch/projectsBuilding.ts @@ -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(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, ] }); }); \ No newline at end of file diff --git a/src/testRunner/unittests/tsbuildWatch/publicApi.ts b/src/testRunner/unittests/tsbuildWatch/publicApi.ts index c58862bff6b..54f00c2fed8 100644 --- a/src/testRunner/unittests/tsbuildWatch/publicApi.ts +++ b/src/testRunner/unittests/tsbuildWatch/publicApi.ts @@ -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, diff --git a/src/testRunner/unittests/tsbuildWatch/reexport.ts b/src/testRunner/unittests/tsbuildWatch/reexport.ts index 23d2857bf01..849403d63dd 100644 --- a/src/testRunner/unittests/tsbuildWatch/reexport.ts +++ b/src/testRunner/unittests/tsbuildWatch/reexport.ts @@ -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 diff --git a/src/testRunner/unittests/tsbuildWatch/watchEnvironment.ts b/src/testRunner/unittests/tsbuildWatch/watchEnvironment.ts index 7021a2ea8a5..e04ddf12f19 100644 --- a/src/testRunner/unittests/tsbuildWatch/watchEnvironment.ts +++ b/src/testRunner/unittests/tsbuildWatch/watchEnvironment.ts @@ -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: [], diff --git a/src/testRunner/unittests/tsc/cancellationToken.ts b/src/testRunner/unittests/tsc/cancellationToken.ts index 21783b336aa..0ea048025bb 100644 --- a/src/testRunner/unittests/tsc/cancellationToken.ts +++ b/src/testRunner/unittests/tsc/cancellationToken.ts @@ -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, diff --git a/src/testRunner/unittests/tsc/composite.ts b/src/testRunner/unittests/tsc/composite.ts index a71001d59f4..f5f274d3a42 100644 --- a/src/testRunner/unittests/tsc/composite.ts +++ b/src/testRunner/unittests/tsc/composite.ts @@ -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"), } ] }); diff --git a/src/testRunner/unittests/tsc/declarationEmit.ts b/src/testRunner/unittests/tsc/declarationEmit.ts index 06ef754312a..09b89121663 100644 --- a/src/testRunner/unittests/tsc/declarationEmit.ts +++ b/src/testRunner/unittests/tsc/declarationEmit.ts @@ -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('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"), }); diff --git a/src/testRunner/unittests/tsc/forceConsistentCasingInFileNames.ts b/src/testRunner/unittests/tsc/forceConsistentCasingInFileNames.ts index 8b1ddf0961b..becde8318e9 100644 --- a/src/testRunner/unittests/tsc/forceConsistentCasingInFileNames.ts +++ b/src/testRunner/unittests/tsc/forceConsistentCasingInFileNames.ts @@ -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"; diff --git a/src/testRunner/unittests/tsc/helpers.ts b/src/testRunner/unittests/tsc/helpers.ts index a8865794eb7..e4ae550d0e9 100644 --- a/src/testRunner/unittests/tsc/helpers.ts +++ b/src/testRunner/unittests/tsc/helpers.ts @@ -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; @@ -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(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 {} +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; }) { + 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 = Omit & { + impliedFormat: string | undefined; + original: T | undefined; +}; +type ReadableProgramMultiFileEmitBuildInfo = Omit & { + fileNamesList: readonly (readonly string[])[] | undefined; + fileInfos: ts.MapLike>; + referencedMap: ts.MapLike | undefined; + exportedModulesMap: ts.MapLike | 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 & { + fileInfos: ts.MapLike>; + pendingEmit: ReadableProgramBuildInfoBundlePendingEmit | undefined; +}; + +type ReadableProgramBuildInfo = ReadableProgramMultiFileEmitBuildInfo | ReadableProgramBundleEmitBuildInfo; + +function isReadableProgramBundleEmitBuildInfo(info: ReadableProgramBuildInfo | undefined): info is ReadableProgramBundleEmitBuildInfo { + return !!info && !!ts.outFile(info.options || {}); +} +type ReadableBuildInfo = Omit & { 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(original: T, toFileInfo: (fileInfo: T) => ts.BuilderState.FileInfo): ReadableProgramBuildInfoFileInfo { + 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 | undefined { + if (!referenceMap) return undefined; + const result: ts.MapLike = {}; + 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(incremental: ts.MapLike | undefined, clean: ts.MapLike | 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(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(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 | ReadableProgramBuildInfoFileInfo, "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`, `/// +const ${file}Const = new ${project}${file}(); +`); +} \ No newline at end of file diff --git a/src/testRunner/unittests/tsc/incremental.ts b/src/testRunner/unittests/tsc/incremental.ts index 972b7efe84a..9bd13a37fb6 100644 --- a/src/testRunner/unittests/tsc/incremental.ts +++ b/src/testRunner/unittests/tsc/incremental.ts @@ -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` /// /// @@ -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`, `/// + prependText(fs, `/src/project/src/main.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 = () =>
;`, @@ -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 = () =>
;`, @@ -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 {
)` }, `\ninterface ReadonlyArray { 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` /// /// @@ -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>; 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 any> = T extends (...args: any) => infer R ? R : any; type InstanceType 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 }), diff --git a/src/testRunner/unittests/tsc/listFilesOnly.ts b/src/testRunner/unittests/tsc/listFilesOnly.ts index a81b1a7c82e..258b0609f94 100644 --- a/src/testRunner/unittests/tsc/listFilesOnly.ts +++ b/src/testRunner/unittests/tsc/listFilesOnly.ts @@ -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"], } ] diff --git a/src/testRunner/unittests/tsc/projectReferences.ts b/src/testRunner/unittests/tsc/projectReferences.ts index 47b9486d02e..98e6c6ad14f 100644 --- a/src/testRunner/unittests/tsc/projectReferences.ts +++ b/src/testRunner/unittests/tsc/projectReferences.ts @@ -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: { diff --git a/src/testRunner/unittests/tsc/redirect.ts b/src/testRunner/unittests/tsc/redirect.ts index df174a6dd54..10925a26181 100644 --- a/src/testRunner/unittests/tsc/redirect.ts +++ b/src/testRunner/unittests/tsc/redirect.ts @@ -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" diff --git a/src/testRunner/unittests/tsc/runWithoutArgs.ts b/src/testRunner/unittests/tsc/runWithoutArgs.ts index 6c7af420523..fa8fe674e9c 100644 --- a/src/testRunner/unittests/tsc/runWithoutArgs.ts +++ b/src/testRunner/unittests/tsc/runWithoutArgs.ts @@ -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" } }); diff --git a/src/testRunner/unittests/tscWatch/consoleClearing.ts b/src/testRunner/unittests/tscWatch/consoleClearing.ts index 7039748e916..856fc8fb368 100644 --- a/src/testRunner/unittests/tscWatch/consoleClearing.ts +++ b/src/testRunner/unittests/tscWatch/consoleClearing.ts @@ -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, }); }); diff --git a/src/testRunner/unittests/tscWatch/emit.ts b/src/testRunner/unittests/tscWatch/emit.ts index 2ab59f8d376..d061b0085c1 100644 --- a/src/testRunner/unittests/tscWatch/emit.ts +++ b/src/testRunner/unittests/tscWatch/emit.ts @@ -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: `/// 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: `/// 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(), } ], }); diff --git a/src/testRunner/unittests/tscWatch/emitAndErrorUpdates.ts b/src/testRunner/unittests/tscWatch/emitAndErrorUpdates.ts index 40afb4bce56..992c2bbb0de 100644 --- a/src/testRunner/unittests/tscWatch/emitAndErrorUpdates.ts +++ b/src/testRunner/unittests/tscWatch/emitAndErrorUpdates.ts @@ -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"; diff --git a/src/testRunner/unittests/tscWatch/forceConsistentCasingInFileNames.ts b/src/testRunner/unittests/tscWatch/forceConsistentCasingInFileNames.ts index f301dc7708b..59bb5fb48cf 100644 --- a/src/testRunner/unittests/tscWatch/forceConsistentCasingInFileNames.ts +++ b/src/testRunner/unittests/tscWatch/forceConsistentCasingInFileNames.ts @@ -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 = () =>
;` }, { - 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, }); diff --git a/src/testRunner/unittests/tscWatch/helpers.ts b/src/testRunner/unittests/tscWatch/helpers.ts index c4d059b896a..03c82333c1e 100644 --- a/src/testRunner/unittests/tscWatch/helpers.ts +++ b/src/testRunner/unittests/tscWatch/helpers.ts @@ -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 = void | ts.SolutionBuilder | ts.WatchOfConfigFile | ts.WatchOfFilesAndCompilerOptions; export interface TscWatchCompileChange { 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 ) => void; } @@ -119,7 +34,7 @@ export interface TscWatchCompileBase[]; } 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; +export type SystemSnap = ReturnType; 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 extends ts.CreateWatchCompilerHostOfConfigFileInput { - system: WatchedSystem, + system: TestServerHost, cb: ts.ExecuteCommandLineCallbacks; } @@ -212,7 +127,7 @@ export function createWatchCompilerHostOfConfigFileForBaseline extends ts.CreateWatchCompilerHostOfFilesAndCompilerOptionsInput { - system: WatchedSystem, + system: TestServerHost, cb: ts.ExecuteCommandLineCallbacks; } export function createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline( @@ -246,8 +161,8 @@ export function applyChange(sys: BaselineBase["sys"], baseline: BaselineBase["ba } export interface RunWatchBaseline extends BaselineBase, TscWatchCompileBase { - sys: ts.TestFSWithWatch.TestServerHostTrackingWrittenFiles; - getPrograms: () => readonly ts.CommandLineProgram[]; + sys: TestServerHostTrackingWrittenFiles; + getPrograms: () => readonly CommandLineProgram[]; watchOrSolution: WatchOrSolution; } export function runWatchBaseline({ @@ -280,7 +195,7 @@ export function runWatchBaseline 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); } diff --git a/src/testRunner/unittests/tscWatch/incremental.ts b/src/testRunner/unittests/tscWatch/incremental.ts index 3de067d433c..fbf7305bd79 100644 --- a/src/testRunner/unittests/tscWatch/incremental.ts +++ b/src/testRunner/unittests/tscWatch/incremental.ts @@ -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 = () =>
;` }, { 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 = () =>
;` }, @@ -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 diff --git a/src/testRunner/unittests/tscWatch/moduleResolution.ts b/src/testRunner/unittests/tscWatch/moduleResolution.ts index ad5894ec250..4631e1bc39e 100644 --- a/src/testRunner/unittests/tscWatch/moduleResolution.ts +++ b/src/testRunner/unittests/tscWatch/moduleResolution.ts @@ -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` /// /// @@ -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`, `/// \n`), + change: sys => sys.prependFile(`/user/username/projects/myproject/a.ts`, `/// \n`), timeouts: sys => sys.runQueuedTimeoutCallbacks(), } ] diff --git a/src/testRunner/unittests/tscWatch/nodeNextWatch.ts b/src/testRunner/unittests/tscWatch/nodeNextWatch.ts index 744b60a1d07..e1eb489fe06 100644 --- a/src/testRunner/unittests/tscWatch/nodeNextWatch.ts +++ b/src/testRunner/unittests/tscWatch/nodeNextWatch.ts @@ -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(), } ], }); diff --git a/src/testRunner/unittests/tscWatch/programUpdates.ts b/src/testRunner/unittests/tscWatch/programUpdates.ts index 725e652d130..6eb0365275c 100644 --- a/src/testRunner/unittests/tscWatch/programUpdates.ts +++ b/src/testRunner/unittests/tscWatch/programUpdates.ts @@ -1,19 +1,22 @@ import * as ts from "../../_namespaces/ts"; import * as Harness from "../../_namespaces/Harness"; +import { createWatchedSystem, File, libFile, SymLink, TestServerHost } from "../virtualFileSystemWithWatch"; +import { commonFile1, commonFile2, createBaseline, createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline, noopChange, runWatchBaseline, TscWatchCompileChange, verifyTscWatch, watchBaseline } from "./helpers"; +import { commandLineCallbacks, compilerOptionsToConfigJson } from "../tsc/helpers"; describe("unittests:: tsc-watch:: program updates", () => { const scenario = "programUpdates"; const configFilePath = "/a/b/tsconfig.json"; - const configFile: ts.tscWatch.File = { + const configFile: File = { path: configFilePath, content: `{}` }; - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "create watch without config file", commandLineArgs: ["-w", "/a/b/c/app.ts"], sys: () => { - const appFile: ts.tscWatch.File = { + const appFile: File = { path: "/a/b/c/app.ts", content: ` import {f} from "./module" @@ -21,16 +24,16 @@ describe("unittests:: tsc-watch:: program updates", () => { ` }; - const moduleFile: ts.tscWatch.File = { + const moduleFile: File = { path: "/a/b/c/module.d.ts", content: `export let x: number` }; - return ts.tscWatch.createWatchedSystem([appFile, moduleFile, ts.tscWatch.libFile]); + return createWatchedSystem([appFile, moduleFile, libFile]); }, changes: ts.emptyArray }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "can handle tsconfig file name with difference casing", commandLineArgs: ["-w", "-p", "/A/B/tsconfig.json"], @@ -45,17 +48,17 @@ describe("unittests:: tsc-watch:: program updates", () => { include: ["app.ts"] }) }; - return ts.tscWatch.createWatchedSystem([f1, ts.tscWatch.libFile, config], { useCaseSensitiveFileNames: false }); + return createWatchedSystem([f1, libFile, config], { useCaseSensitiveFileNames: false }); }, changes: ts.emptyArray }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "create configured project without file list", commandLineArgs: ["-w", "-p", configFilePath], sys: () => { - const configFile: ts.tscWatch.File = { + const configFile: File = { path: configFilePath, content: ` { @@ -65,43 +68,43 @@ describe("unittests:: tsc-watch:: program updates", () => { ] }` }; - const file1: ts.tscWatch.File = { + const file1: File = { path: "/a/b/c/f1.ts", content: "let x = 1" }; - const file2: ts.tscWatch.File = { + const file2: File = { path: "/a/b/d/f2.ts", content: "let y = 1" }; - const file3: ts.tscWatch.File = { + const file3: File = { path: "/a/b/e/f3.ts", content: "let z = 1" }; - return ts.tscWatch.createWatchedSystem([configFile, ts.tscWatch.libFile, file1, file2, file3]); + return createWatchedSystem([configFile, libFile, file1, file2, file3]); }, changes: ts.emptyArray }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "add new files to a configured program without file list", commandLineArgs: ["-w", "-p", configFilePath], - sys: () => ts.tscWatch.createWatchedSystem([ts.tscWatch.commonFile1, ts.tscWatch.libFile, configFile]), + sys: () => createWatchedSystem([commonFile1, libFile, configFile]), changes: [ { caption: "Create commonFile2", - change: sys => sys.writeFile(ts.tscWatch.commonFile2.path, ts.tscWatch.commonFile2.content), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + change: sys => sys.writeFile(commonFile2.path, commonFile2.content), + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), } ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "should ignore non-existing files specified in the config file", commandLineArgs: ["-w", "-p", configFilePath], sys: () => { - const configFile: ts.tscWatch.File = { + const configFile: File = { path: configFilePath, content: `{ "compilerOptions": {}, @@ -111,131 +114,131 @@ describe("unittests:: tsc-watch:: program updates", () => { ] }` }; - return ts.tscWatch.createWatchedSystem([ts.tscWatch.commonFile1, ts.tscWatch.commonFile2, ts.tscWatch.libFile, configFile]); + return createWatchedSystem([commonFile1, commonFile2, libFile, configFile]); }, changes: ts.emptyArray }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "handle recreated files correctly", commandLineArgs: ["-w", "-p", configFilePath, "--explainFiles"], sys: () => { - return ts.tscWatch.createWatchedSystem([ts.tscWatch.libFile, ts.tscWatch.commonFile1, ts.tscWatch.commonFile2, configFile]); + return createWatchedSystem([libFile, commonFile1, commonFile2, configFile]); }, changes: [ { caption: "change file to ensure signatures are updated", - change: sys => sys.appendFile(ts.tscWatch.commonFile2.path, ";let xy = 10;"), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + change: sys => sys.appendFile(commonFile2.path, ";let xy = 10;"), + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), }, { caption: "delete file2", - change: sys => sys.deleteFile(ts.tscWatch.commonFile2.path), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + change: sys => sys.deleteFile(commonFile2.path), + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), }, { caption: "recreate file2", - change: sys => sys.writeFile(ts.tscWatch.commonFile2.path, ts.tscWatch.commonFile2.content), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + change: sys => sys.writeFile(commonFile2.path, commonFile2.content), + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), } ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "handles the missing files - that were added to program because they were added with tripleSlashRefs", commandLineArgs: ["-w", "/a/b/commonFile1.ts"], sys: () => { - const file1: ts.tscWatch.File = { - path: ts.tscWatch.commonFile1.path, + const file1: File = { + path: commonFile1.path, content: `/// let x = y` }; - return ts.tscWatch.createWatchedSystem([file1, ts.tscWatch.libFile]); + return createWatchedSystem([file1, libFile]); }, changes: [ { caption: "create file2", - change: sys => sys.writeFile(ts.tscWatch.commonFile2.path, ts.tscWatch.commonFile2.content), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + change: sys => sys.writeFile(commonFile2.path, commonFile2.content), + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), } ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "should reflect change in config file", commandLineArgs: ["-w", "-p", configFilePath, "--explainFiles"], sys: () => { - const configFile: ts.tscWatch.File = { + const configFile: File = { path: configFilePath, content: `{ "compilerOptions": {}, - "files": ["${ts.tscWatch.commonFile1.path}", "${ts.tscWatch.commonFile2.path}"] + "files": ["${commonFile1.path}", "${commonFile2.path}"] }` }; - return ts.tscWatch.createWatchedSystem([ts.tscWatch.libFile, ts.tscWatch.commonFile1, ts.tscWatch.commonFile2, configFile]); + return createWatchedSystem([libFile, commonFile1, commonFile2, configFile]); }, changes: [ { caption: "change file to ensure signatures are updated", - change: sys => sys.appendFile(ts.tscWatch.commonFile2.path, ";let xy = 10;"), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + change: sys => sys.appendFile(commonFile2.path, ";let xy = 10;"), + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), }, { caption: "Change config", change: sys => sys.writeFile(configFilePath, `{ "compilerOptions": {}, - "files": ["${ts.tscWatch.commonFile1.path}"] + "files": ["${commonFile1.path}"] }`), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), } ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "works correctly when config file is changed but its content havent", commandLineArgs: ["-w", "-p", configFilePath], sys: () => { - const configFile: ts.tscWatch.File = { + const configFile: File = { path: configFilePath, content: `{ "compilerOptions": {}, - "files": ["${ts.tscWatch.commonFile1.path}", "${ts.tscWatch.commonFile2.path}"] + "files": ["${commonFile1.path}", "${commonFile2.path}"] }` }; - return ts.tscWatch.createWatchedSystem([ts.tscWatch.libFile, ts.tscWatch.commonFile1, ts.tscWatch.commonFile2, configFile]); + return createWatchedSystem([libFile, commonFile1, commonFile2, configFile]); }, changes: [ { caption: "Modify config without changing content", change: sys => sys.modifyFile(configFilePath, `{ "compilerOptions": {}, - "files": ["${ts.tscWatch.commonFile1.path}", "${ts.tscWatch.commonFile2.path}"] + "files": ["${commonFile1.path}", "${commonFile2.path}"] }`), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), } ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "Updates diagnostics when '--noUnusedLabels' changes", commandLineArgs: ["-w", "-p", "/tsconfig.json"], sys: () => { - const aTs: ts.tscWatch.File = { + const aTs: File = { path: "/a.ts", content: "label: while (1) {}" }; - const tsconfig: ts.tscWatch.File = { + const tsconfig: File = { path: "/tsconfig.json", content: JSON.stringify({ compilerOptions: { allowUnusedLabels: true } }) }; - return ts.tscWatch.createWatchedSystem([ts.tscWatch.libFile, aTs, tsconfig]); + return createWatchedSystem([libFile, aTs, tsconfig]); }, changes: [ { @@ -243,24 +246,24 @@ describe("unittests:: tsc-watch:: program updates", () => { change: sys => sys.modifyFile("/tsconfig.json", JSON.stringify({ compilerOptions: { allowUnusedLabels: false } })), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1) }, { caption: "Enable allowUnsusedLabels", change: sys => sys.modifyFile("/tsconfig.json", JSON.stringify({ compilerOptions: { allowUnusedLabels: true } })), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), } ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "updates diagnostics and emit for decorators", commandLineArgs: ["-w"], sys: () => { - const aTs: ts.tscWatch.File = { + const aTs: File = { path: "/a.ts", content: `import {B} from './b' @((_) => {}) @@ -268,17 +271,17 @@ export class A { constructor(p: B) {} }`, }; - const bTs: ts.tscWatch.File = { + const bTs: File = { path: "/b.ts", content: `export class B {}`, }; - const tsconfig: ts.tscWatch.File = { + const tsconfig: File = { path: "/tsconfig.json", content: JSON.stringify({ compilerOptions: { target: "es6", importsNotUsedAsValues: "error" } }) }; - return ts.tscWatch.createWatchedSystem([ts.tscWatch.libFile, aTs, bTs, tsconfig]); + return createWatchedSystem([libFile, aTs, bTs, tsconfig]); }, changes: [ { @@ -286,7 +289,7 @@ export class A { change: sys => sys.modifyFile("/tsconfig.json", JSON.stringify({ compilerOptions: { target: "es6", importsNotUsedAsValues: "error", experimentalDecorators: true } })), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), }, { @@ -294,50 +297,50 @@ export class A { change: sys => sys.modifyFile("/tsconfig.json", JSON.stringify({ compilerOptions: { target: "es6", importsNotUsedAsValues: "error", experimentalDecorators: true, emitDecoratorMetadata: true } })), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), } ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "files explicitly excluded in config file", commandLineArgs: ["-w", "-p", configFilePath], sys: () => { - const configFile: ts.tscWatch.File = { + const configFile: File = { path: configFilePath, content: `{ "compilerOptions": {}, "exclude": ["/a/c"] }` }; - const excludedFile1: ts.tscWatch.File = { + const excludedFile1: File = { path: "/a/c/excluedFile1.ts", content: `let t = 1;` }; - return ts.tscWatch.createWatchedSystem([ts.tscWatch.libFile, ts.tscWatch.commonFile1, ts.tscWatch.commonFile2, excludedFile1, configFile]); + return createWatchedSystem([libFile, commonFile1, commonFile2, excludedFile1, configFile]); }, changes: ts.emptyArray }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "should properly handle module resolution changes in config file", commandLineArgs: ["-w", "-p", configFilePath], sys: () => { - const file1: ts.tscWatch.File = { + const file1: File = { path: "/a/b/file1.ts", content: `import { T } from "module1";` }; - const nodeModuleFile: ts.tscWatch.File = { + const nodeModuleFile: File = { path: "/a/b/node_modules/module1.ts", content: `export interface T {}` }; - const classicModuleFile: ts.tscWatch.File = { + const classicModuleFile: File = { path: "/a/module1.ts", content: `export interface T {}` }; - const configFile: ts.tscWatch.File = { + const configFile: File = { path: configFilePath, content: `{ "compilerOptions": { @@ -346,7 +349,7 @@ export class A { "files": ["${file1.path}"] }` }; - return ts.tscWatch.createWatchedSystem([ts.tscWatch.libFile, file1, nodeModuleFile, classicModuleFile, configFile]); + return createWatchedSystem([libFile, file1, nodeModuleFile, classicModuleFile, configFile]); }, changes: [ { @@ -357,17 +360,17 @@ export class A { }, "files": ["/a/b/file1.ts"] }`), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), } ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "should tolerate config file errors and still try to build a project", commandLineArgs: ["-w", "-p", configFilePath], sys: () => { - const configFile: ts.tscWatch.File = { + const configFile: File = { path: configFilePath, content: `{ "compilerOptions": { @@ -377,12 +380,12 @@ export class A { "someOtherProperty": {} }` }; - return ts.tscWatch.createWatchedSystem([ts.tscWatch.commonFile1, ts.tscWatch.commonFile2, ts.tscWatch.libFile, configFile]); + return createWatchedSystem([commonFile1, commonFile2, libFile, configFile]); }, changes: ts.emptyArray }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "changes in files are reflected in project structure", commandLineArgs: ["-w", "/a/b/f1.ts", "--explainFiles"], @@ -399,19 +402,19 @@ export class A { path: "/a/c/f3.ts", content: `export let y = 1;` }; - return ts.tscWatch.createWatchedSystem([file1, file2, file3, ts.tscWatch.libFile]); + return createWatchedSystem([file1, file2, file3, libFile]); }, changes: [ { caption: "Modify f2 to include f3", // now inferred project should inclule file3 change: sys => sys.modifyFile("/a/b/f2.ts", `export * from "../c/f3"`), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), } ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "deleted files affect project structure", commandLineArgs: ["-w", "/a/b/f1.ts", "--noImplicitAny"], @@ -428,18 +431,18 @@ export class A { path: "/a/c/f3.ts", content: `export let y = 1;` }; - return ts.tscWatch.createWatchedSystem([file1, file2, file3, ts.tscWatch.libFile]); + return createWatchedSystem([file1, file2, file3, libFile]); }, changes: [ { caption: "Delete f2", change: sys => sys.deleteFile("/a/b/f2.ts"), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), } ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "deleted files affect project structure-2", commandLineArgs: ["-w", "/a/b/f1.ts", "/a/c/f3.ts", "--noImplicitAny"], @@ -456,18 +459,18 @@ export class A { path: "/a/c/f3.ts", content: `export let y = 1;` }; - return ts.tscWatch.createWatchedSystem([file1, file2, file3, ts.tscWatch.libFile]); + return createWatchedSystem([file1, file2, file3, libFile]); }, changes: [ { caption: "Delete f2", change: sys => sys.deleteFile("/a/b/f2.ts"), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), } ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "config file includes the file", commandLineArgs: ["-w", "-p", "/a/c/tsconfig.json"], @@ -488,12 +491,12 @@ export class A { path: "/a/c/tsconfig.json", content: JSON.stringify({ compilerOptions: {}, files: ["f2.ts", "f3.ts"] }) }; - return ts.tscWatch.createWatchedSystem([file1, file2, file3, ts.tscWatch.libFile, configFile]); + return createWatchedSystem([file1, file2, file3, libFile, configFile]); }, changes: ts.emptyArray }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "change module to none", commandLineArgs: ["-w", "-p", configFilePath], @@ -502,11 +505,11 @@ export class A { path: "/a/b/f1.ts", content: "export {}\ndeclare global {}" }; - return ts.tscWatch.createWatchedSystem([file1, ts.tscWatch.libFile, configFile]); + return createWatchedSystem([file1, libFile, configFile]); }, changes: [{ caption: "change `module` to 'none'", - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), change: sys => { sys.writeFile(configFilePath, JSON.stringify({ compilerOptions: { module: "none" } })); } @@ -528,8 +531,8 @@ export class A { path: "/a/d/f3.ts", content: "export let y = 1;" }; - const { sys, baseline, oldSnap, cb, getPrograms } = ts.tscWatch.createBaseline(ts.tscWatch.createWatchedSystem([ts.tscWatch.libFile, file1, file2, file3])); - const host = ts.tscWatch.createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline({ + const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem([libFile, file1, file2, file3])); + const host = createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline({ rootFiles: [file2.path, file3.path], system: sys, options: { allowNonTsExtensions: true }, @@ -538,7 +541,7 @@ export class A { }); ts.createWatchProgram(host); baseline.push(`${sys.getExecutingFilePath()} --w ${file2.path} ${file3.path}`); - ts.tscWatch.watchBaseline({ + watchBaseline({ baseline, getPrograms, oldPrograms: ts.emptyArray, @@ -546,17 +549,17 @@ export class A { oldSnap, }); - const {cb: cb2, getPrograms: getPrograms2 } = ts.commandLineCallbacks(sys); + const {cb: cb2, getPrograms: getPrograms2 } = commandLineCallbacks(sys); const oldSnap2 = sys.snap(); baseline.push("createing separate watcher"); - ts.createWatchProgram(ts.tscWatch.createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline({ + ts.createWatchProgram(createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline({ rootFiles:[file1.path], system: sys, options: { allowNonTsExtensions: true }, cb: cb2, watchOptions: undefined })); - ts.tscWatch.watchBaseline({ + watchBaseline({ baseline, getPrograms: getPrograms2, oldPrograms: ts.emptyArray, @@ -570,7 +573,7 @@ export class A { Harness.Baseline.runBaseline(`tscWatch/${scenario}/two-watch-programs-are-not-affected-by-each-other.js`, baseline.join("\r\n")); }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "can correctly update configured project when set of root files has changed (new file on disk)", commandLineArgs: ["-w", "-p", configFilePath], @@ -579,18 +582,18 @@ export class A { path: "/a/b/f1.ts", content: "let x = 1" }; - return ts.tscWatch.createWatchedSystem([file1, ts.tscWatch.libFile, configFile]); + return createWatchedSystem([file1, libFile, configFile]); }, changes: [ { caption: "Write f2", change: sys => sys.writeFile("/a/b/f2.ts", "let y = 1"), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), } ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "can correctly update configured project when set of root files has changed (new file in list of files)", commandLineArgs: ["-w", "-p", configFilePath], @@ -607,75 +610,75 @@ export class A { path: configFilePath, content: JSON.stringify({ compilerOptions: {}, files: ["f1.ts"] }) }; - return ts.tscWatch.createWatchedSystem([file1, file2, ts.tscWatch.libFile, configFile]); + return createWatchedSystem([file1, file2, libFile, configFile]); }, changes: [ { caption: "Modify config to make f2 as root too", change: sys => sys.writeFile(configFilePath, JSON.stringify({ compilerOptions: {}, files: ["f1.ts", "f2.ts"] })), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), } ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "correctly parses wild card directories from implicit glob when two keys differ only in directory seperator", commandLineArgs: ["-w", "--extendedDiagnostics"], sys: () => { const file1 = { - path: `${ts.tscWatch.projectRoot}/f1.ts`, + path: `/user/username/projects/myproject/f1.ts`, content: "export const x = 1" }; const file2 = { - path: `${ts.tscWatch.projectRoot}/f2.ts`, + path: `/user/username/projects/myproject/f2.ts`, content: "export const y = 1" }; const configFile = { - path: `${ts.tscWatch.projectRoot}/tsconfig.json`, + path: `/user/username/projects/myproject/tsconfig.json`, content: JSON.stringify({ compilerOptions: { composite: true }, include: ["./", "./**/*.json"] }) }; - return ts.tscWatch.createWatchedSystem([file1, file2, ts.tscWatch.libFile, configFile], { currentDirectory: ts.tscWatch.projectRoot }); + return createWatchedSystem([file1, file2, libFile, configFile], { currentDirectory: "/user/username/projects/myproject" }); }, changes: [ { caption: "Add new file", - change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/new-file.ts`, "export const z = 1;"), + change: sys => sys.writeFile(`/user/username/projects/myproject/new-file.ts`, "export const z = 1;"), timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), }, { caption: "Import new file", - change: sys => sys.prependFile(`${ts.tscWatch.projectRoot}/f1.ts`, `import { z } from "./new-file";`), + change: sys => sys.prependFile(`/user/username/projects/myproject/f1.ts`, `import { z } from "./new-file";`), timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), } ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "can correctly update configured project when set of root files has changed through include", commandLineArgs: ["-w", "-p", "."], sys: () => { const file1 = { - path: `${ts.tscWatch.projectRoot}/Project/file1.ts`, + path: `/user/username/projects/myproject/Project/file1.ts`, content: "export const x = 10;" }; const configFile = { - path: `${ts.tscWatch.projectRoot}/Project/tsconfig.json`, + path: `/user/username/projects/myproject/Project/tsconfig.json`, content: JSON.stringify({ include: [".", "./**/*.json"] }) }; - return ts.tscWatch.createWatchedSystem([file1, ts.tscWatch.libFile, configFile], { currentDirectory: `${ts.tscWatch.projectRoot}/Project` }); + return createWatchedSystem([file1, libFile, configFile], { currentDirectory: `/user/username/projects/myproject/Project` }); }, changes: [ { caption: "Write file2", - change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/Project/file2.ts`, "export const y = 10;"), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun + change: sys => sys.writeFile(`/user/username/projects/myproject/Project/file2.ts`, "export const y = 10;"), + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1) } ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "can update configured project when set of root files was not changed", commandLineArgs: ["-w", "-p", configFilePath], @@ -692,18 +695,18 @@ export class A { path: configFilePath, content: JSON.stringify({ compilerOptions: {}, files: ["f1.ts", "f2.ts"] }) }; - return ts.tscWatch.createWatchedSystem([file1, file2, ts.tscWatch.libFile, configFile]); + return createWatchedSystem([file1, file2, libFile, configFile]); }, changes: [ { caption: "Modify config to set outFile option", change: sys => sys.writeFile(configFilePath, JSON.stringify({ compilerOptions: { outFile: "out.js" }, files: ["f1.ts", "f2.ts"] })), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), } ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "file in files is deleted", commandLineArgs: ["-w", "-p", configFilePath], @@ -720,18 +723,18 @@ export class A { path: configFilePath, content: JSON.stringify({ compilerOptions: {}, files: ["f1.ts", "f2.ts"] }) }; - return ts.tscWatch.createWatchedSystem([file1, file2, ts.tscWatch.libFile, configFile]); + return createWatchedSystem([file1, file2, libFile, configFile]); }, changes: [ { caption: "Delete f2", change: sys => sys.deleteFile("/a/b/f2.ts"), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), } ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "config file is deleted", commandLineArgs: ["-w", "-p", configFilePath], @@ -744,18 +747,18 @@ export class A { path: "/a/b/f2.ts", content: "let y = 2;" }; - return ts.tscWatch.createWatchedSystem([file1, file2, ts.tscWatch.libFile, configFile]); + return createWatchedSystem([file1, file2, libFile, configFile]); }, changes: [ { caption: "Delete config file", change: sys => sys.deleteFile(configFilePath), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), } ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "Proper errors document is not contained in project", commandLineArgs: ["-w", "-p", configFilePath], @@ -768,19 +771,19 @@ export class A { path: configFilePath, content: "{" }; - return ts.tscWatch.createWatchedSystem([file1, ts.tscWatch.libFile, corruptedConfig]); + return createWatchedSystem([file1, libFile, corruptedConfig]); }, changes: ts.emptyArray }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "correctly handles changes in lib section of config file", commandLineArgs: ["-w", "-p", "/src/tsconfig.json"], sys: () => { const libES5 = { path: "/compiler/lib.es5.d.ts", - content: `${ts.tscWatch.libFile.content} + content: `${libFile.content} declare const eval: any` }; const libES2015Promise = { @@ -806,7 +809,7 @@ declare const eval: any` } }) }; - return ts.tscWatch.createWatchedSystem([libES5, libES2015Promise, app, config1], { executingFilePath: "/compiler/tsc.js" }); + return createWatchedSystem([libES5, libES2015Promise, app, config1], { executingFilePath: "/compiler/tsc.js" }); }, changes: [ { @@ -825,12 +828,12 @@ declare const eval: any` } }) ), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), } ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "should handle non-existing directories in config file", commandLineArgs: ["-w", "-p", "/a/tsconfig.json"], @@ -849,17 +852,17 @@ declare const eval: any` ] }) }; - return ts.tscWatch.createWatchedSystem([f, config, ts.tscWatch.libFile]); + return createWatchedSystem([f, config, libFile]); }, changes: ts.emptyArray }); - function runQueuedTimeoutCallbacksTwice(sys: ts.tscWatch.WatchedSystem) { + function runQueuedTimeoutCallbacksTwice(sys: TestServerHost) { sys.runQueuedTimeoutCallbacks(); // Scheduled invalidation of resolutions sys.runQueuedTimeoutCallbacks(); // Actual update } - const changeModuleFileToModuleFile1: ts.tscWatch.TscWatchCompileChange = { + const changeModuleFileToModuleFile1: TscWatchCompileChange = { caption: "Rename moduleFile to moduleFile1", change: sys => { sys.renameFile("/a/b/moduleFile.ts", "/a/b/moduleFile1.ts"); @@ -867,13 +870,13 @@ declare const eval: any` }, timeouts: runQueuedTimeoutCallbacksTwice }; - const changeModuleFile1ToModuleFile: ts.tscWatch.TscWatchCompileChange = { + const changeModuleFile1ToModuleFile: TscWatchCompileChange = { caption: "Rename moduleFile1 back to moduleFile", change: sys => sys.renameFile("/a/b/moduleFile1.ts", "/a/b/moduleFile.ts"), timeouts: runQueuedTimeoutCallbacksTwice, }; - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "rename a module file and rename back should restore the states for inferred projects", commandLineArgs: ["-w", "/a/b/file1.ts"], @@ -886,7 +889,7 @@ declare const eval: any` path: "/a/b/file1.ts", content: 'import * as T from "./moduleFile"; T.bar();' }; - return ts.tscWatch.createWatchedSystem([moduleFile, file1, ts.tscWatch.libFile]); + return createWatchedSystem([moduleFile, file1, libFile]); }, changes: [ changeModuleFileToModuleFile1, @@ -894,7 +897,7 @@ declare const eval: any` ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "rename a module file and rename back should restore the states for configured projects", commandLineArgs: ["-w", "-p", configFilePath], @@ -907,7 +910,7 @@ declare const eval: any` path: "/a/b/file1.ts", content: 'import * as T from "./moduleFile"; T.bar();' }; - return ts.tscWatch.createWatchedSystem([moduleFile, file1, configFile, ts.tscWatch.libFile]); + return createWatchedSystem([moduleFile, file1, configFile, libFile]); }, changes: [ changeModuleFileToModuleFile1, @@ -915,7 +918,7 @@ declare const eval: any` ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "types should load from config file path if config exists", commandLineArgs: ["-w", "-p", configFilePath], @@ -935,12 +938,12 @@ declare const eval: any` const cwd = { path: "/a/c" }; - return ts.tscWatch.createWatchedSystem([f1, config, node, cwd, ts.tscWatch.libFile], { currentDirectory: cwd.path }); + return createWatchedSystem([f1, config, node, cwd, libFile], { currentDirectory: cwd.path }); }, changes: ts.emptyArray }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "add the missing module file for inferred project-should remove the module not found error", commandLineArgs: ["-w", "/a/b/file1.ts"], @@ -949,7 +952,7 @@ declare const eval: any` path: "/a/b/file1.ts", content: 'import * as T from "./moduleFile"; T.bar();' }; - return ts.tscWatch.createWatchedSystem([file1, ts.tscWatch.libFile]); + return createWatchedSystem([file1, libFile]); }, changes: [ { @@ -960,7 +963,7 @@ declare const eval: any` ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "Configure file diagnostics events are generated when the config file has errors", commandLineArgs: ["-w", "-p", configFilePath], @@ -978,12 +981,12 @@ declare const eval: any` } }` }; - return ts.tscWatch.createWatchedSystem([file, configFile, ts.tscWatch.libFile]); + return createWatchedSystem([file, configFile, libFile]); }, changes: ts.emptyArray }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "if config file doesnt have errors, they are not reported", commandLineArgs: ["-w", "-p", configFilePath], @@ -998,12 +1001,12 @@ declare const eval: any` "compilerOptions": {} }` }; - return ts.tscWatch.createWatchedSystem([file, configFile, ts.tscWatch.libFile]); + return createWatchedSystem([file, configFile, libFile]); }, changes: ts.emptyArray }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "Reports errors when the config file changes", commandLineArgs: ["-w", "-p", configFilePath], @@ -1012,7 +1015,7 @@ declare const eval: any` path: "/a/b/app.ts", content: "let x = 10" }; - return ts.tscWatch.createWatchedSystem([file, configFile, ts.tscWatch.libFile]); + return createWatchedSystem([file, configFile, libFile]); }, changes: [ { @@ -1022,7 +1025,7 @@ declare const eval: any` "haha": 123 } }`), - timeouts: ts.tscWatch.runQueuedTimeoutCallbacks, + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "change config file to remove error", @@ -1030,12 +1033,12 @@ declare const eval: any` "compilerOptions": { } }`), - timeouts: ts.tscWatch.runQueuedTimeoutCallbacks, + timeouts: sys => sys.runQueuedTimeoutCallbacks(), } ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "non-existing directories listed in config file input array should be tolerated without crashing the server", commandLineArgs: ["-w", "-p", configFilePath], @@ -1051,12 +1054,12 @@ declare const eval: any` path: "/a/b/file1.ts", content: "let t = 10;" }; - return ts.tscWatch.createWatchedSystem([file1, configFile, ts.tscWatch.libFile]); + return createWatchedSystem([file1, configFile, libFile]); }, changes: ts.emptyArray }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "non-existing directories listed in config file input array should be able to handle @types if input file list is empty", commandLineArgs: ["-w", "-p", "/a/tsconfig.json"], @@ -1080,7 +1083,7 @@ declare const eval: any` path: "/a/node_modules/@types/typings/lib.d.ts", content: `export const x: number` }; - return ts.tscWatch.createWatchedSystem([f, config, t1, t2, ts.tscWatch.libFile], { currentDirectory: ts.getDirectoryPath(f.path) }); + return createWatchedSystem([f, config, t1, t2, libFile], { currentDirectory: ts.getDirectoryPath(f.path) }); }, changes: ts.emptyArray }); @@ -1090,15 +1093,15 @@ declare const eval: any` path: "/a/compile", content: "let x = 1" }; - const { sys, baseline, oldSnap, cb, getPrograms } = ts.tscWatch.createBaseline(ts.tscWatch.createWatchedSystem([f, ts.tscWatch.libFile])); - const watch = ts.createWatchProgram(ts.tscWatch.createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline({ + const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem([f, libFile])); + const watch = ts.createWatchProgram(createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline({ rootFiles: [f.path], system: sys, options: { allowNonTsExtensions: true }, cb, watchOptions: undefined })); - ts.tscWatch.runWatchBaseline({ + runWatchBaseline({ scenario, subScenario: "should support files without extensions", commandLineArgs: ["--w", f.path], @@ -1111,7 +1114,7 @@ declare const eval: any` }); }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "Options Diagnostic locations reported correctly with changes in configFile contents when options change", commandLineArgs: ["-w", "-p", configFilePath], @@ -1132,7 +1135,7 @@ declare const eval: any` } }` }; - return ts.tscWatch.createWatchedSystem([file, ts.tscWatch.libFile, configFile]); + return createWatchedSystem([file, libFile, configFile]); }, changes: [ { @@ -1144,42 +1147,42 @@ declare const eval: any` "mapRoot": "./" } }`), - timeouts: ts.tscWatch.runQueuedTimeoutCallbacks, + timeouts: sys => sys.runQueuedTimeoutCallbacks(), } ] }); describe("should not trigger recompilation because of program emit", () => { function verifyWithOptions(subScenario: string, options: ts.CompilerOptions) { - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: `should not trigger recompilation because of program emit/${subScenario}`, - commandLineArgs: ["-w", "-p", `${ts.tscWatch.projectRoot}/tsconfig.json`], + commandLineArgs: ["-w", "-p", `/user/username/projects/myproject/tsconfig.json`], sys: () => { - const file1: ts.tscWatch.File = { - path: `${ts.tscWatch.projectRoot}/file1.ts`, + const file1: File = { + path: `/user/username/projects/myproject/file1.ts`, content: "export const c = 30;" }; - const file2: ts.tscWatch.File = { - path: `${ts.tscWatch.projectRoot}/src/file2.ts`, + const file2: File = { + path: `/user/username/projects/myproject/src/file2.ts`, content: `import {c} from "file1"; export const d = 30;` }; - 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: ts.compilerOptionsToConfigJson(options) + compilerOptions: compilerOptionsToConfigJson(options) }) }; - return ts.tscWatch.createWatchedSystem([file1, file2, ts.tscWatch.libFile, tsconfig], { currentDirectory: ts.tscWatch.projectRoot }); + return createWatchedSystem([file1, file2, libFile, tsconfig], { currentDirectory: "/user/username/projects/myproject" }); }, changes: [ - ts.tscWatch.noopChange, + noopChange, { caption: "Add new file", - change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/src/file3.ts`, `export const y = 10;`), + change: sys => sys.writeFile(`/user/username/projects/myproject/src/file3.ts`, `export const y = 10;`), timeouts: sys => sys.checkTimeoutQueueLengthAndRun(2), // To update program and failed lookups }, - ts.tscWatch.noopChange, + noopChange, ] }); } @@ -1215,12 +1218,12 @@ declare const eval: any` ); }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "shouldnt report error about unused function incorrectly when file changes from global to module", commandLineArgs: ["-w", "/a/b/file.ts", "--noUnusedLocals"], sys: () => { - const file: ts.tscWatch.File = { + const file: File = { path: "/a/b/file.ts", content: `function one() {} function two() { @@ -1229,7 +1232,7 @@ function two() { } }` }; - return ts.tscWatch.createWatchedSystem([file, ts.tscWatch.libFile]); + return createWatchedSystem([file, libFile]); }, changes: [ { @@ -1240,64 +1243,64 @@ export function two() { one(); } }`), - timeouts: ts.tscWatch.runQueuedTimeoutCallbacks, + timeouts: sys => sys.runQueuedTimeoutCallbacks(), } ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "watched files when file is deleted and new file is added as part of change", commandLineArgs: ["-w", "-p", "/home/username/project/tsconfig.json"], sys: () => { const projectLocation = "/home/username/project"; - const file: ts.tscWatch.File = { + const file: File = { path: `${projectLocation}/src/file1.ts`, content: "var a = 10;" }; - const configFile: ts.tscWatch.File = { + const configFile: File = { path: `${projectLocation}/tsconfig.json`, content: "{}" }; - return ts.tscWatch.createWatchedSystem([file, ts.tscWatch.libFile, configFile]); + return createWatchedSystem([file, libFile, configFile]); }, changes: [ { caption: "Rename file1 to file2", change: sys => sys.renameFile("/home/username/project/src/file1.ts", "/home/username/project/src/file2.ts"), - timeouts: ts.tscWatch.runQueuedTimeoutCallbacks, + timeouts: sys => sys.runQueuedTimeoutCallbacks(), } ] }); - function changeParameterTypeOfBFile(parameterName: string, toType: string): ts.tscWatch.TscWatchCompileChange { + function changeParameterTypeOfBFile(parameterName: string, toType: string): TscWatchCompileChange { return { caption: `Changed ${parameterName} type to ${toType}`, - change: sys => ts.tscWatch.replaceFileText(sys, `${ts.tscWatch.projectRoot}/b.ts`, new RegExp(`${parameterName}\: [a-z]*`), `${parameterName}: ${toType}`), - timeouts: ts.tscWatch.runQueuedTimeoutCallbacks, + change: sys => sys.replaceFileText(`/user/username/projects/myproject/b.ts`, new RegExp(`${parameterName}\: [a-z]*`), `${parameterName}: ${toType}`), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }; } - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "updates errors correctly when declaration emit is disabled in compiler options", commandLineArgs: ["-w"], sys: () => { - const aFile: ts.tscWatch.File = { - path: `${ts.tscWatch.projectRoot}/a.ts`, + const aFile: File = { + path: `/user/username/projects/myproject/a.ts`, content: `import test from './b'; test(4, 5);` }; - const bFile: ts.tscWatch.File = { - path: `${ts.tscWatch.projectRoot}/b.ts`, + const bFile: File = { + path: `/user/username/projects/myproject/b.ts`, content: `function test(x: number, y: number) { return x + y / 5; } export default test;` }; - const tsconfigFile: ts.tscWatch.File = { - path: `${ts.tscWatch.projectRoot}/tsconfig.json`, + const tsconfigFile: File = { + path: `/user/username/projects/myproject/tsconfig.json`, content: JSON.stringify({ compilerOptions: { module: "commonjs", @@ -1306,7 +1309,7 @@ export default test;` } }) }; - return ts.tscWatch.createWatchedSystem([aFile, bFile, ts.tscWatch.libFile, tsconfigFile], { currentDirectory: ts.tscWatch.projectRoot }); + return createWatchedSystem([aFile, bFile, libFile, tsconfigFile], { currentDirectory: "/user/username/projects/myproject" }); }, changes: [ changeParameterTypeOfBFile("x", "string"), @@ -1316,48 +1319,48 @@ export default test;` ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "updates errors when strictNullChecks changes", commandLineArgs: ["-w"], sys: () => { - const aFile: ts.tscWatch.File = { - path: `${ts.tscWatch.projectRoot}/a.ts`, + const aFile: File = { + path: `/user/username/projects/myproject/a.ts`, content: `declare function foo(): null | { hello: any }; foo().hello` }; - 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: {} }) }; - return ts.tscWatch.createWatchedSystem([aFile, config, ts.tscWatch.libFile], { currentDirectory: ts.tscWatch.projectRoot }); + return createWatchedSystem([aFile, config, libFile], { currentDirectory: "/user/username/projects/myproject" }); }, changes: [ { caption: "Enable strict null checks", - change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/tsconfig.json`, JSON.stringify({ compilerOptions: { strictNullChecks: true } })), - timeouts: ts.tscWatch.runQueuedTimeoutCallbacks, + change: sys => sys.writeFile(`/user/username/projects/myproject/tsconfig.json`, JSON.stringify({ compilerOptions: { strictNullChecks: true } })), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Set always strict false", - change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/tsconfig.json`, JSON.stringify({ compilerOptions: { strict: true, alwaysStrict: false } })), // Avoid changing 'alwaysStrict' or must re-bind - timeouts: ts.tscWatch.runQueuedTimeoutCallbacks, + change: sys => sys.writeFile(`/user/username/projects/myproject/tsconfig.json`, JSON.stringify({ compilerOptions: { strict: true, alwaysStrict: false } })), // Avoid changing 'alwaysStrict' or must re-bind + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Disable strict", - change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/tsconfig.json`, JSON.stringify({ compilerOptions: {} })), - timeouts: ts.tscWatch.runQueuedTimeoutCallbacks, + change: sys => sys.writeFile(`/user/username/projects/myproject/tsconfig.json`, JSON.stringify({ compilerOptions: {} })), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "updates errors when noErrorTruncation changes", commandLineArgs: ["-w"], sys: () => { - const aFile: ts.tscWatch.File = { - path: `${ts.tscWatch.projectRoot}/a.ts`, + const aFile: File = { + path: `/user/username/projects/myproject/a.ts`, content: `declare var v: { reallyLongPropertyName1: string | number | boolean | object | symbol | bigint; reallyLongPropertyName2: string | number | boolean | object | symbol | bigint; @@ -1369,172 +1372,172 @@ foo().hello` }; v === 'foo';` }; - 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: {} }) }; - return ts.tscWatch.createWatchedSystem([aFile, config, ts.tscWatch.libFile], { currentDirectory: ts.tscWatch.projectRoot }); + return createWatchedSystem([aFile, config, libFile], { currentDirectory: "/user/username/projects/myproject" }); }, changes: [ { caption: "Enable noErrorTruncation", - change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/tsconfig.json`, JSON.stringify({ compilerOptions: { noErrorTruncation: true } })), - timeouts: ts.tscWatch.runQueuedTimeoutCallbacks, + change: sys => sys.writeFile(`/user/username/projects/myproject/tsconfig.json`, JSON.stringify({ compilerOptions: { noErrorTruncation: true } })), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "updates diagnostics and emit when useDefineForClassFields changes", commandLineArgs: ["-w"], sys: () => { - const aFile: ts.tscWatch.File = { + const aFile: File = { path: `/a.ts`, content: `class C { get prop() { return 1; } } class D extends C { prop = 1; }` }; - const config: ts.tscWatch.File = { + const config: File = { path: `/tsconfig.json`, content: JSON.stringify({ compilerOptions: { target: "es6" } }) }; - return ts.tscWatch.createWatchedSystem([aFile, config, ts.tscWatch.libFile]); + return createWatchedSystem([aFile, config, libFile]); }, changes: [ { caption: "Enable useDefineForClassFields", change: sys => sys.writeFile(`/tsconfig.json`, JSON.stringify({ compilerOptions: { target: "es6", useDefineForClassFields: true } })), - timeouts: ts.tscWatch.runQueuedTimeoutCallbacks, + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "updates errors and emit when importsNotUsedAsValues changes", commandLineArgs: ["-w"], sys: () => { - const aFile: ts.tscWatch.File = { - path: `${ts.tscWatch.projectRoot}/a.ts`, + const aFile: File = { + path: `/user/username/projects/myproject/a.ts`, content: `export class C {}` }; - 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 './a'; export function f(p: C) { return p; }` }; - 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: {} }) }; - return ts.tscWatch.createWatchedSystem([aFile, bFile, config, ts.tscWatch.libFile], { currentDirectory: ts.tscWatch.projectRoot }); + return createWatchedSystem([aFile, bFile, config, libFile], { currentDirectory: "/user/username/projects/myproject" }); }, changes: [ { caption: 'Set to "remove"', - change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/tsconfig.json`, JSON.stringify({ compilerOptions: { importsNotUsedAsValues: "remove" } })), - timeouts: ts.tscWatch.runQueuedTimeoutCallbacks, + change: sys => sys.writeFile(`/user/username/projects/myproject/tsconfig.json`, JSON.stringify({ compilerOptions: { importsNotUsedAsValues: "remove" } })), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: 'Set to "error"', - change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/tsconfig.json`, JSON.stringify({ compilerOptions: { importsNotUsedAsValues: "error" } })), - timeouts: ts.tscWatch.runQueuedTimeoutCallbacks, + change: sys => sys.writeFile(`/user/username/projects/myproject/tsconfig.json`, JSON.stringify({ compilerOptions: { importsNotUsedAsValues: "error" } })), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: 'Set to "preserve"', - change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/tsconfig.json`, JSON.stringify({ compilerOptions: { importsNotUsedAsValues: "preserve" } })), - timeouts: ts.tscWatch.runQueuedTimeoutCallbacks, + change: sys => sys.writeFile(`/user/username/projects/myproject/tsconfig.json`, JSON.stringify({ compilerOptions: { importsNotUsedAsValues: "preserve" } })), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "updates errors when forceConsistentCasingInFileNames changes", commandLineArgs: ["-w"], sys: () => { - const aFile: ts.tscWatch.File = { + const aFile: File = { path: `/a.ts`, content: `export class C {}` }; - const bFile: ts.tscWatch.File = { + const bFile: File = { path: `/b.ts`, content: `import {C} from './a'; import * as A from './A';` }; - const config: ts.tscWatch.File = { + const config: File = { path: `/tsconfig.json`, content: JSON.stringify({ compilerOptions: {} }) }; - return ts.tscWatch.createWatchedSystem([aFile, bFile, config, ts.tscWatch.libFile], { useCaseSensitiveFileNames: false }); + return createWatchedSystem([aFile, bFile, config, libFile], { useCaseSensitiveFileNames: false }); }, changes: [ { caption: "Enable forceConsistentCasingInFileNames", change: sys => sys.writeFile(`/tsconfig.json`, JSON.stringify({ compilerOptions: { forceConsistentCasingInFileNames: true } })), - timeouts: ts.tscWatch.runQueuedTimeoutCallbacks, + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "updates moduleResolution when resolveJsonModule changes", commandLineArgs: ["-w"], sys: () => { - const aFile: ts.tscWatch.File = { - path: `${ts.tscWatch.projectRoot}/a.ts`, + const aFile: File = { + path: `/user/username/projects/myproject/a.ts`, content: `import * as data from './data.json'` }; - const jsonFile: ts.tscWatch.File = { - path: `${ts.tscWatch.projectRoot}/data.json`, + const jsonFile: File = { + path: `/user/username/projects/myproject/data.json`, content: `{ "foo": 1 }` }; - 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: { moduleResolution: "node" } }) }; - return ts.tscWatch.createWatchedSystem([aFile, jsonFile, config, ts.tscWatch.libFile], { currentDirectory: ts.tscWatch.projectRoot }); + return createWatchedSystem([aFile, jsonFile, config, libFile], { currentDirectory: "/user/username/projects/myproject" }); }, changes: [ { caption: "Enable resolveJsonModule", - change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/tsconfig.json`, JSON.stringify({ compilerOptions: { moduleResolution: "node", resolveJsonModule: true } })), - timeouts: ts.tscWatch.runQueuedTimeoutCallbacks, + change: sys => sys.writeFile(`/user/username/projects/myproject/tsconfig.json`, JSON.stringify({ compilerOptions: { moduleResolution: "node", resolveJsonModule: true } })), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "updates errors when ambient modules of program changes", commandLineArgs: ["-w"], sys: () => { - const aFile: ts.tscWatch.File = { - path: `${ts.tscWatch.projectRoot}/a.ts`, + const aFile: File = { + path: `/user/username/projects/myproject/a.ts`, content: `declare module 'a' { type foo = number; }` }; - 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([aFile, config, ts.tscWatch.libFile], { currentDirectory: ts.tscWatch.projectRoot }); + return createWatchedSystem([aFile, config, libFile], { currentDirectory: "/user/username/projects/myproject" }); }, changes: [ { caption: "Create b.ts with same content", // Create bts with same file contents - change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/b.ts`, `declare module 'a' { + change: sys => sys.writeFile(`/user/username/projects/myproject/b.ts`, `declare module 'a' { type foo = number; }`), - timeouts: ts.tscWatch.runQueuedTimeoutCallbacks, + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Delete b.ts", - change: sys => sys.deleteFile(`${ts.tscWatch.projectRoot}/b.ts`), - timeouts: ts.tscWatch.runQueuedTimeoutCallbacks, + change: sys => sys.deleteFile(`/user/username/projects/myproject/b.ts`), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, ] }); @@ -1545,31 +1548,31 @@ export function f(p: C) { return p; }` ${field}: boolean; }`; - const libFileWithDocument: ts.tscWatch.File = { - path: ts.tscWatch.libFile.path, - content: `${ts.tscWatch.libFile.content} + const libFileWithDocument: File = { + path: libFile.path, + content: `${libFile.content} interface Document { readonly ${field}: boolean; }` }; - function verifyLibFileErrorsWith(subScenario: string, aFile: ts.tscWatch.File) { + function verifyLibFileErrorsWith(subScenario: string, aFile: File) { function verifyLibErrors(subScenario: string, commandLineOptions: readonly string[]) { - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: `updates errors in lib file/${subScenario}`, commandLineArgs: ["-w", aFile.path, ...commandLineOptions], - sys: () => ts.tscWatch.createWatchedSystem([aFile, libFileWithDocument], { currentDirectory: ts.tscWatch.projectRoot }), + sys: () => createWatchedSystem([aFile, libFileWithDocument], { currentDirectory: "/user/username/projects/myproject" }), changes: [ { caption: "Remove document declaration from file", change: sys => sys.writeFile(aFile.path, aFile.content.replace(fieldWithoutReadonly, "var x: string;")), - timeouts: ts.tscWatch.runQueuedTimeoutCallbacks, + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Rever the file to contain document declaration", change: sys => sys.writeFile(aFile.path, aFile.content), - timeouts: ts.tscWatch.runQueuedTimeoutCallbacks, + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, ] }); @@ -1581,8 +1584,8 @@ interface Document { } describe("when non module file changes", () => { - const aFile: ts.tscWatch.File = { - path: `${ts.tscWatch.projectRoot}/a.ts`, + const aFile: File = { + path: `/user/username/projects/myproject/a.ts`, content: `${fieldWithoutReadonly} var y: number;` }; @@ -1590,8 +1593,8 @@ var y: number;` }); describe("when module file with global definitions changes", () => { - const aFile: ts.tscWatch.File = { - path: `${ts.tscWatch.projectRoot}/a.ts`, + const aFile: File = { + path: `/user/username/projects/myproject/a.ts`, content: `export {} declare global { ${fieldWithoutReadonly} @@ -1602,45 +1605,45 @@ var y: number; }); }); - function changeWhenLibCheckChanges(compilerOptions: ts.CompilerOptions): ts.tscWatch.TscWatchCompileChange { + function changeWhenLibCheckChanges(compilerOptions: ts.CompilerOptions): TscWatchCompileChange { const configFileContent = JSON.stringify({ compilerOptions }); return { caption: `Changing config to ${configFileContent}`, - change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/tsconfig.json`, configFileContent), - timeouts: ts.tscWatch.runQueuedTimeoutCallbacks, + change: sys => sys.writeFile(`/user/username/projects/myproject/tsconfig.json`, configFileContent), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }; } - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "when skipLibCheck and skipDefaultLibCheck changes", commandLineArgs: ["-w"], sys: () => { const field = "fullscreen"; - const aFile: ts.tscWatch.File = { - path: `${ts.tscWatch.projectRoot}/a.ts`, + const aFile: File = { + path: `/user/username/projects/myproject/a.ts`, content: `interface Document { ${field}: boolean; }` }; - const bFile: ts.tscWatch.File = { - path: `${ts.tscWatch.projectRoot}/b.d.ts`, + const bFile: File = { + path: `/user/username/projects/myproject/b.d.ts`, content: `interface Document { ${field}: boolean; }` }; - const libFileWithDocument: ts.tscWatch.File = { - path: ts.tscWatch.libFile.path, - content: `${ts.tscWatch.libFile.content} + const libFileWithDocument: File = { + path: libFile.path, + content: `${libFile.content} interface Document { readonly ${field}: boolean; }` }; - const configFile: ts.tscWatch.File = { - path: `${ts.tscWatch.projectRoot}/tsconfig.json`, + const configFile: File = { + path: `/user/username/projects/myproject/tsconfig.json`, content: "{}" }; - return ts.tscWatch.createWatchedSystem([aFile, bFile, configFile, libFileWithDocument], { currentDirectory: ts.tscWatch.projectRoot }); + return createWatchedSystem([aFile, bFile, configFile, libFileWithDocument], { currentDirectory: "/user/username/projects/myproject" }); }, changes: [ changeWhenLibCheckChanges({ skipLibCheck: true }), @@ -1652,54 +1655,54 @@ interface Document { ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "reports errors correctly with isolatedModules", commandLineArgs: ["-w"], sys: () => { - const aFile: ts.tscWatch.File = { - path: `${ts.tscWatch.projectRoot}/a.ts`, + const aFile: File = { + path: `/user/username/projects/myproject/a.ts`, content: `export const a: string = "";` }; - const bFile: ts.tscWatch.File = { - path: `${ts.tscWatch.projectRoot}/b.ts`, + const bFile: File = { + path: `/user/username/projects/myproject/b.ts`, content: `import { a } from "./a"; const b: string = a;` }; - 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: { isolatedModules: true } }) }; - return ts.tscWatch.createWatchedSystem([aFile, bFile, configFile, ts.tscWatch.libFile], { currentDirectory: ts.tscWatch.projectRoot }); + return createWatchedSystem([aFile, bFile, configFile, libFile], { currentDirectory: "/user/username/projects/myproject" }); }, changes: [ { caption: "Change shape of a", - change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/a.ts`, `export const a: number = 1`), - timeouts: ts.tscWatch.runQueuedTimeoutCallbacks, + change: sys => sys.writeFile(`/user/username/projects/myproject/a.ts`, `export const a: number = 1`), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "reports errors correctly with file not in rootDir", commandLineArgs: ["-w"], sys: () => { - const aFile: ts.tscWatch.File = { - path: `${ts.tscWatch.projectRoot}/a.ts`, + const aFile: File = { + path: `/user/username/projects/myproject/a.ts`, content: `import { x } from "../b";` }; - const bFile: ts.tscWatch.File = { + const bFile: File = { path: `/user/username/projects/b.ts`, content: `export const x = 10;` }; - 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: { rootDir: ".", @@ -1707,53 +1710,53 @@ const b: string = a;` } }) }; - return ts.tscWatch.createWatchedSystem([aFile, bFile, configFile, ts.tscWatch.libFile], { currentDirectory: ts.tscWatch.projectRoot }); + return createWatchedSystem([aFile, bFile, configFile, libFile], { currentDirectory: "/user/username/projects/myproject" }); }, changes: [ { caption: "Make changes to file a", - change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/a.ts`, ` + change: sys => sys.writeFile(`/user/username/projects/myproject/a.ts`, ` import { x } from "../b";`), - timeouts: ts.tscWatch.runQueuedTimeoutCallbacks, + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "updates emit on jsx option change", commandLineArgs: ["-w"], sys: () => { - const index: ts.tscWatch.File = { - path: `${ts.tscWatch.projectRoot}/index.tsx`, + const index: File = { + path: `/user/username/projects/myproject/index.tsx`, content: `declare var React: any;\nconst d =
;` }; - 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: { jsx: "preserve" } }) }; - 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: "Update 'jsx' to 'react'", - change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/tsconfig.json`, '{ "compilerOptions": { "jsx": "react" } }'), - timeouts: ts.tscWatch.runQueuedTimeoutCallbacks, + change: sys => sys.writeFile(`/user/username/projects/myproject/tsconfig.json`, '{ "compilerOptions": { "jsx": "react" } }'), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "extended source files are watched", commandLineArgs: ["-w", "-p", configFilePath], sys: () => { - const firstExtendedConfigFile: ts.tscWatch.File = { + const firstExtendedConfigFile: File = { path: "/a/b/first.tsconfig.json", content: JSON.stringify({ compilerOptions: { @@ -1761,21 +1764,21 @@ import { x } from "../b";`), } }) }; - const secondExtendedConfigFile: ts.tscWatch.File = { + const secondExtendedConfigFile: File = { path: "/a/b/second.tsconfig.json", content: JSON.stringify({ extends: "./first.tsconfig.json" }) }; - const configFile: ts.tscWatch.File = { + const configFile: File = { path: configFilePath, content: JSON.stringify({ compilerOptions: {}, - files: [ts.tscWatch.commonFile1.path, ts.tscWatch.commonFile2.path] + files: [commonFile1.path, commonFile2.path] }) }; - return ts.tscWatch.createWatchedSystem([ - ts.tscWatch.libFile, ts.tscWatch.commonFile1, ts.tscWatch.commonFile2, configFile, firstExtendedConfigFile, secondExtendedConfigFile + return createWatchedSystem([ + libFile, commonFile1, commonFile2, configFile, firstExtendedConfigFile, secondExtendedConfigFile ]); }, changes: [ @@ -1784,9 +1787,9 @@ import { x } from "../b";`), change: sys => sys.modifyFile(configFilePath, JSON.stringify({ extends: "./second.tsconfig.json", compilerOptions: {}, - files: [ts.tscWatch.commonFile1.path, ts.tscWatch.commonFile2.path] + files: [commonFile1.path, commonFile2.path] })), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), }, { caption: "Change first extended config", @@ -1795,7 +1798,7 @@ import { x } from "../b";`), strict: false, } })), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), }, { caption: "Change second extended config", @@ -1805,38 +1808,38 @@ import { x } from "../b";`), strictNullChecks: true, } })), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), }, { caption: "Change config to stop extending another config", change: sys => sys.modifyFile(configFilePath, JSON.stringify({ compilerOptions: {}, - files: [ts.tscWatch.commonFile1.path, ts.tscWatch.commonFile2.path] + files: [commonFile1.path, commonFile2.path] })), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), }, ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "when creating new file in symlinked folder", commandLineArgs: ["-w", "-p", ".", "--extendedDiagnostics"], sys: () => { - const module1: ts.tscWatch.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.tscWatch.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.tscWatch.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.tscWatch.File = { - path: `${ts.tscWatch.projectRoot}/tsconfig.json`, + const config: File = { + path: `/user/username/projects/myproject/tsconfig.json`, content: JSON.stringify({ compilerOptions: { baseUrl: "client", @@ -1845,24 +1848,24 @@ import { x } from "../b";`), include: ["client/**/*", "folder2"] }) }; - return ts.tscWatch.createWatchedSystem([module1, module2, symlink, config, ts.tscWatch.libFile], { currentDirectory: ts.tscWatch.projectRoot }); + return createWatchedSystem([module1, module2, symlink, config, libFile], { currentDirectory: "/user/username/projects/myproject" }); }, changes: [ { caption: "Add module3 to folder2", - change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/client/linktofolder2/module3.ts`, `import * as M from "folder1/module1";`), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + change: sys => sys.writeFile(`/user/username/projects/myproject/client/linktofolder2/module3.ts`, `import * as M from "folder1/module1";`), + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), }, ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "when new file is added to the referenced project", - commandLineArgs: ["-w", "-p", `${ts.tscWatch.projectRoot}/projects/project2/tsconfig.json`, "--extendedDiagnostics"], + commandLineArgs: ["-w", "-p", `/user/username/projects/myproject/projects/project2/tsconfig.json`, "--extendedDiagnostics"], sys: () => { - 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", @@ -1871,17 +1874,17 @@ import { x } from "../b";`), 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 {}` }; // Built file - const class1Dt: ts.tscWatch.File = { - path: `${ts.tscWatch.projectRoot}/projects/project1/class1.d.ts`, + const class1Dt: 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", @@ -1892,61 +1895,61 @@ import { x } from "../b";`), ] }) }; - 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 {}` }; - return ts.tscWatch.createWatchedSystem([config1, class1, config2, class2, ts.tscWatch.libFile, class1Dt]); + return createWatchedSystem([config1, class1, config2, class2, libFile, class1Dt]); }, changes: [ { caption: "Add class3 to project1", - change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/projects/project1/class3.ts`, `class class3 {}`), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + change: sys => sys.writeFile(`/user/username/projects/myproject/projects/project1/class3.ts`, `class class3 {}`), + 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), }, { 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), }, ] }); - ts.tscWatch.verifyTscWatch({ + verifyTscWatch({ scenario, subScenario: "when creating extensionless file", commandLineArgs: ["-w", "-p", ".", "--extendedDiagnostics"], sys: () => { - const module1: ts.tscWatch.File = { - path: `${ts.tscWatch.projectRoot}/index.ts`, + const module1: File = { + path: `/user/username/projects/myproject/index.ts`, content: `` }; - 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([module1, config, ts.tscWatch.libFile], { currentDirectory: ts.tscWatch.projectRoot }); + return createWatchedSystem([module1, config, libFile], { currentDirectory: "/user/username/projects/myproject" }); }, changes: [ { caption: "Create foo in project root", - change: sys => sys.writeFile(`${ts.tscWatch.projectRoot}/foo`, ``), - timeouts: ts.tscWatch.checkSingleTimeoutQueueLengthAndRun, + change: sys => sys.writeFile(`/user/username/projects/myproject/foo`, ``), + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), }, ] }); diff --git a/src/testRunner/unittests/tscWatch/projectsWithReferences.ts b/src/testRunner/unittests/tscWatch/projectsWithReferences.ts index 6a9d3566140..37ca5221386 100644 --- a/src/testRunner/unittests/tscWatch/projectsWithReferences.ts +++ b/src/testRunner/unittests/tscWatch/projectsWithReferences.ts @@ -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), diff --git a/src/testRunner/unittests/tscWatch/resolutionCache.ts b/src/testRunner/unittests/tscWatch/resolutionCache.ts index df69419ac6c..51075802121 100644 --- a/src/testRunner/unittests/tscWatch/resolutionCache.ts +++ b/src/testRunner/unittests/tscWatch/resolutionCache.ts @@ -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: `/// ` }; - 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: /// ` }; - 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: `/// ` }; - 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`, diff --git a/src/testRunner/unittests/tscWatch/sourceOfProjectReferenceRedirect.ts b/src/testRunner/unittests/tscWatch/sourceOfProjectReferenceRedirect.ts index 7be526e3952..23589d5a52f 100644 --- a/src/testRunner/unittests/tscWatch/sourceOfProjectReferenceRedirect.ts +++ b/src/testRunner/unittests/tscWatch/sourceOfProjectReferenceRedirect.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" : ""}` })); diff --git a/src/testRunner/unittests/tscWatch/watchApi.ts b/src/testRunner/unittests/tscWatch/watchApi.ts index 9f8219610b2..80f056255d7 100644 --- a/src/testRunner/unittests/tscWatch/watchApi.ts +++ b/src/testRunner/unittests/tscWatch/watchApi.ts @@ -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( baseline: string[], - config: ts.tscWatch.File, - sys: ts.TestFSWithWatch.TestServerHostTrackingWrittenFiles, + config: File, + sys: TestServerHostTrackingWrittenFiles, createProgram: ts.CreateProgram, 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({ + const host = createWatchCompilerHostOfConfigFileForBaseline({ 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( 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, 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", diff --git a/src/testRunner/unittests/tscWatch/watchEnvironment.ts b/src/testRunner/unittests/tscWatch/watchEnvironment.ts index ddeeaa64c5c..859c152fea1 100644 --- a/src/testRunner/unittests/tscWatch/watchEnvironment.ts +++ b/src/testRunner/unittests/tscWatch/watchEnvironment.ts @@ -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(); - 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(); 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(); 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), }, ] diff --git a/src/testRunner/unittests/tsserver/applyChangesToOpenFiles.ts b/src/testRunner/unittests/tsserver/applyChangesToOpenFiles.ts index f778e721398..1eefb848ce3 100644 --- a/src/testRunner/unittests/tsserver/applyChangesToOpenFiles.ts +++ b/src/testRunner/unittests/tsserver/applyChangesToOpenFiles.ts @@ -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({ - command: ts.projectSystem.protocol.CommandTypes.Open, + const host = createServerHost([app, file3, commonFile1, commonFile2, libFile, configFile]); + const session = createSession(host); + session.executeCommandSeq({ + 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({ - command: ts.projectSystem.protocol.CommandTypes.Open, + session.executeCommandSeq({ + 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({ - command: ts.projectSystem.protocol.CommandTypes.ApplyChangedToOpenFiles, + applyChangesToOpen: session => session.executeCommandSeq({ + 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({ - command: ts.projectSystem.protocol.CommandTypes.ApplyChangedToOpenFiles, + openFile1Again: session => session.executeCommandSeq({ + 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({ - command: ts.projectSystem.protocol.CommandTypes.UpdateOpen, + applyChangesToOpen: session => session.executeCommandSeq({ + 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({ - command: ts.projectSystem.protocol.CommandTypes.UpdateOpen, + openFile1Again: session => session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.UpdateOpen, arguments: { openFiles: [{ - file: ts.projectSystem.commonFile1.path, - fileContent: ts.projectSystem.commonFile1.content + file: commonFile1.path, + fileContent: commonFile1.content }] } }), diff --git a/src/testRunner/unittests/tsserver/autoImportProvider.ts b/src/testRunner/unittests/tsserver/autoImportProvider.ts index 5d2113bb64e..ba3442ad9e6 100644 --- a/src/testRunner/unittests/tsserver/autoImportProvider.ts +++ b/src/testRunner/unittests/tsserver/autoImportProvider.ts @@ -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({ - command: ts.projectSystem.protocol.CommandTypes.ApplyChangedToOpenFiles, + session.executeCommandSeq({ + 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({ - command: ts.projectSystem.protocol.CommandTypes.References, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.References, arguments: { file, line, diff --git a/src/testRunner/unittests/tsserver/auxiliaryProject.ts b/src/testRunner/unittests/tsserver/auxiliaryProject.ts index 58742f0e421..0538634c682 100644 --- a/src/testRunner/unittests/tsserver/auxiliaryProject.ts +++ b/src/testRunner/unittests/tsserver/auxiliaryProject.ts @@ -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); diff --git a/src/testRunner/unittests/tsserver/cachingFileSystemInformation.ts b/src/testRunner/unittests/tsserver/cachingFileSystemInformation.ts index 5834c4592ca..16e82192623 100644 --- a/src/testRunner/unittests/tsserver/cachingFileSystemInformation.ts +++ b/src/testRunner/unittests/tsserver/cachingFileSystemInformation.ts @@ -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> & Record> = { 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.CommandTypes.Definition, { + const getDefinitionRequest = makeSessionRequest(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`]); }); }); diff --git a/src/testRunner/unittests/tsserver/cancellationToken.ts b/src/testRunner/unittests/tsserver/cancellationToken.ts index 5c207e74d8e..84c1b914e41 100644 --- a/src/testRunner/unittests/tsserver/cancellationToken.ts +++ b/src/testRunner/unittests/tsserver/cancellationToken.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(request: Partial) { diff --git a/src/testRunner/unittests/tsserver/compileOnSave.ts b/src/testRunner/unittests/tsserver/compileOnSave.ts index 327dfdef426..39ba6857b07 100644 --- a/src/testRunner/unittests/tsserver/compileOnSave.ts +++ b/src/testRunner/unittests/tsserver/compileOnSave.ts @@ -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(CommandNames.Change, { + changeModuleFile1ShapeRequest1 = makeSessionRequest(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(CommandNames.Change, { + changeModuleFile1InternalRequest1 = makeSessionRequest(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(CommandNames.CompileOnSaveAffectedFileList, { file: moduleFile1.path, projectFileName: configFile.path }); + moduleFile1FileListRequest = makeSessionRequest(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(CommandNames.Change, { + const changeFile1InternalRequest = makeSessionRequest(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(CommandNames.Change, { + const removeFile1Consumer1ImportRequest = makeSessionRequest(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(CommandNames.Change, { + const addFile2ImportRequest = makeSessionRequest(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(CommandNames.Change, { + const changeModuleFile1ShapeRequest2 = makeSessionRequest(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(CommandNames.Change, { + openFilesForSession([globalFile3], session); + const changeGlobalFile3ShapeRequest = makeSessionRequest(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(CommandNames.CompileOnSaveAffectedFileList, { file: globalFile3.path }); + const globalFile3FileListRequest = makeSessionRequest(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(CommandNames.Change, { + const file1ChangeShapeRequest = makeSessionRequest(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(CommandNames.Change, { + const file1ChangeShapeRequest = makeSessionRequest(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(CommandNames.Change, { + const changeFile1Consumer1ShapeRequest = makeSessionRequest(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: ` /// export var t1 = 10;` }; - const file2: ts.projectSystem.File = { + const file2: File = { path: "/a/b/file2.ts", content: ` /// 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(CommandNames.CompileOnSaveAffectedFileList, { file: file1.path }); + openFilesForSession([file1, file2], session); + const file1AffectedListRequest = makeSessionRequest(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(CommandNames.CompileOnSaveAffectedFileList, { file: file1.path }); + openFilesForSession([file1, file2, file3], session); + const file1AffectedListRequest = makeSessionRequest(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: ` /// 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(CommandNames.CompileOnSaveAffectedFileList, { file: referenceFile1.path }); + const request = makeSessionRequest(ts.server.CommandNames.CompileOnSaveAffectedFileList, { file: referenceFile1.path }); sendAffectedFileRequestAndCheckResult(session, request, [ { projectFileName: configFile.path, files: [referenceFile1] } ]); - const requestForMissingFile = ts.projectSystem.makeSessionRequest(CommandNames.CompileOnSaveAffectedFileList, { file: moduleFile1.path }); + const requestForMissingFile = makeSessionRequest(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: ` /// 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(CommandNames.CompileOnSaveAffectedFileList, { file: referenceFile1.path }); + openFilesForSession([referenceFile1], session); + const request = makeSessionRequest(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({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + const host = createServerHost([f1, f2, config]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([f1], session); + session.executeCommandSeq({ + 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(CommandNames.CompileOnSaveEmitFile, { file: file1.path, projectFileName: configFile.path }); + openFilesForSession([file1, file2], session); + const compileFileRequest = makeSessionRequest(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(CommandNames.CompileOnSaveEmitFile, { file: file1.path }); + const emitRequest = makeSessionRequest(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(CommandNames.CompileOnSaveEmitFile, { file: file1.path }); + const emitRequest = makeSessionRequest(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({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + const affectedFileResponse = session.executeCommandSeq({ + 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({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + const file1SaveResponse = session.executeCommandSeq({ + 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({ - 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({ + 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({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + const affectedFileResponse = session.executeCommandSeq({ + 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({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + function verifyFileSave(file: File) { + const response = session.executeCommandSeq({ + 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({ - command: ts.projectSystem.protocol.CommandTypes.UpdateOpen, + session.executeCommandSeq({ + 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({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + const affectedFileResponse = session.executeCommandSeq({ + 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({ - command: ts.projectSystem.protocol.CommandTypes.Change, + function insertString(session: TestSession, file: File) { + session.executeCommandSeq({ + 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({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + 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`, }); }); diff --git a/src/testRunner/unittests/tsserver/completions.ts b/src/testRunner/unittests/tsserver/completions.ts index 4e046ae6eba..59852f1fdb8 100644 --- a/src/testRunner/unittests/tsserver/completions.ts +++ b/src/testRunner/unittests/tsserver/completions.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(session, ts.projectSystem.protocol.CommandTypes.CompletionInfo, { + const response = executeSessionRequest(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(response, { + assert.deepEqual(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(session, ts.projectSystem.protocol.CommandTypes.CompletionDetails, detailsRequestArgs); - const detailsCommon: ts.projectSystem.protocol.CompletionEntryDetails & ts.CompletionEntryDetails = { + const detailsResponse = executeSessionRequest(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(detailsResponse, [ + assert.deepEqual(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(session, ts.projectSystem.protocol.CommandTypes.CompletionDetailsFull, detailsRequestArgs); + const detailsFullResponse = executeSessionRequest(session, ts.server.protocol.CommandTypes.CompletionDetailsFull, detailsRequestArgs); assert.deepEqual(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({ - 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({ + command: ts.server.protocol.CommandTypes.CompletionInfo, arguments: { file: appFile.path, line: 5, diff --git a/src/testRunner/unittests/tsserver/completionsIncomplete.ts b/src/testRunner/unittests/tsserver/completionsIncomplete.ts index e0d3ee5ed4e..2088ed57d0a 100644 --- a/src/testRunner/unittests/tsserver/completionsIncomplete.ts +++ b/src/testRunner/unittests/tsserver/completionsIncomplete.ts @@ -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({ - command: ts.projectSystem.protocol.CommandTypes.Configure, + session.executeCommandSeq({ + 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({ - command: ts.projectSystem.protocol.CommandTypes.UpdateOpen, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.UpdateOpen, arguments: { changedFiles: [{ fileName, @@ -186,22 +188,22 @@ function setup(files: ts.projectSystem.File[]) { }, }); - const response = session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompletionInfo, + const response = session.executeCommandSeq({ + 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({ - command: ts.projectSystem.protocol.CommandTypes.UpdateOpen, + session.executeCommandSeq({ + 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({ - command: ts.projectSystem.protocol.CommandTypes.CompletionDetails, + const details = session.executeCommandSeq({ + 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); diff --git a/src/testRunner/unittests/tsserver/configFileSearch.ts b/src/testRunner/unittests/tsserver/configFileSearch.ts index 8ed168c683b..d264aba5619 100644 --- a/src/testRunner/unittests/tsserver/configFileSearch.ts +++ b/src/testRunner/unittests/tsserver/configFileSearch.ts @@ -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); diff --git a/src/testRunner/unittests/tsserver/configuredProjects.ts b/src/testRunner/unittests/tsserver/configuredProjects.ts index 9e3ebe7e5ae..a8c107f48ce 100644 --- a/src/testRunner/unittests/tsserver/configuredProjects.ts +++ b/src/testRunner/unittests/tsserver/configuredProjects.ts @@ -1,8 +1,11 @@ import * as ts from "../../_namespaces/ts"; +import { createServerHost, File, libFile, SymLink } from "../virtualFileSystemWithWatch"; +import { commonFile1, commonFile2, ensureErrorFreeBuild } from "../tscWatch/helpers"; +import { createProjectService, createLoggerWithInMemoryLogs, baselineTsserverLogs, checkNumberOfConfiguredProjects, configuredProjectAt, checkProjectRootFiles, checkNumberOfInferredProjects, checkNumberOfProjects, checkProjectActualFiles, createSessionWithEventTracking, createSession, openFilesForSession, verifyGetErrRequest } from "./helpers"; describe("unittests:: tsserver:: ConfiguredProjects", () => { it("create configured project without file list", () => { - const configFile: ts.projectSystem.File = { + const configFile: File = { path: "/a/b/tsconfig.json", content: ` { @@ -12,31 +15,31 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { ] }` }; - const file1: ts.projectSystem.File = { + const file1: File = { path: "/a/b/c/f1.ts", content: "let x = 1" }; - const file2: ts.projectSystem.File = { + const file2: File = { path: "/a/b/d/f2.ts", content: "let y = 1" }; - const file3: ts.projectSystem.File = { + const file3: File = { path: "/a/b/e/f3.ts", content: "let z = 1" }; - const host = ts.projectSystem.createServerHost([configFile, ts.projectSystem.libFile, file1, file2, file3]); - const projectService = ts.projectSystem.createProjectService(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); + const host = createServerHost([configFile, libFile, file1, file2, file3]); + const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); const { configFileName, configFileErrors } = projectService.openClientFile(file1.path); assert(configFileName, "should find config file"); assert.isTrue(!configFileErrors || configFileErrors.length === 0, `expect no errors in config file, got ${JSON.stringify(configFileErrors)}`); - ts.projectSystem.baselineTsserverLogs("configuredProjects", "create configured project without file list", projectService); + baselineTsserverLogs("configuredProjects", "create configured project without file list", projectService); }); it("create configured project with the file list", () => { - const configFile: ts.projectSystem.File = { + const configFile: File = { path: "/a/b/tsconfig.json", content: ` { @@ -44,48 +47,48 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { "include": ["*.ts"] }` }; - const file1: ts.projectSystem.File = { + const file1: File = { path: "/a/b/f1.ts", content: "let x = 1" }; - const file2: ts.projectSystem.File = { + const file2: File = { path: "/a/b/f2.ts", content: "let y = 1" }; - const file3: ts.projectSystem.File = { + const file3: File = { path: "/a/b/c/f3.ts", content: "let z = 1" }; - const host = ts.projectSystem.createServerHost([configFile, ts.projectSystem.libFile, file1, file2, file3]); - const projectService = ts.projectSystem.createProjectService(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); + const host = createServerHost([configFile, libFile, file1, file2, file3]); + const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); const { configFileName, configFileErrors } = projectService.openClientFile(file1.path); assert(configFileName, "should find config file"); assert.isTrue(!configFileErrors || configFileErrors.length === 0, `expect no errors in config file, got ${JSON.stringify(configFileErrors)}`); - ts.projectSystem.baselineTsserverLogs("configuredProjects", "create configured project with the file list", projectService); + baselineTsserverLogs("configuredProjects", "create configured project with the file list", projectService); }); it("add and then remove a config file in a folder with loose files", () => { - const configFile: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/tsconfig.json`, + const configFile: File = { + path: `/user/username/projects/myproject/tsconfig.json`, content: `{ "files": ["commonFile1.ts"] }` }; - const commonFile1: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/commonFile1.ts`, + const commonFile1: File = { + path: `/user/username/projects/myproject/commonFile1.ts`, content: "let x = 1" }; - const commonFile2: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/commonFile2.ts`, + const commonFile2: File = { + path: `/user/username/projects/myproject/commonFile2.ts`, content: "let y = 1" }; - const host = ts.projectSystem.createServerHost([ts.projectSystem.libFile, commonFile1, commonFile2]); + const host = createServerHost([libFile, commonFile1, commonFile2]); - const projectService = ts.projectSystem.createProjectService(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); + const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); projectService.openClientFile(commonFile1.path); projectService.openClientFile(commonFile2.path); @@ -97,26 +100,26 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { host.deleteFile(configFile.path); host.checkTimeoutQueueLengthAndRun(1); // Refresh inferred projects - ts.projectSystem.baselineTsserverLogs("configuredProjects", "add and then remove a config file in a folder with loose files", projectService); + baselineTsserverLogs("configuredProjects", "add and then remove a config file in a folder with loose files", projectService); }); it("add new files to a configured project without file list", () => { - const configFile: ts.projectSystem.File = { + const configFile: File = { path: "/a/b/tsconfig.json", content: `{}` }; - const host = ts.projectSystem.createServerHost([ts.projectSystem.commonFile1, ts.projectSystem.libFile, configFile]); - const projectService = ts.projectSystem.createProjectService(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - projectService.openClientFile(ts.projectSystem.commonFile1.path); + const host = createServerHost([commonFile1, libFile, configFile]); + const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); + projectService.openClientFile(commonFile1.path); // add a new ts file - host.writeFile(ts.projectSystem.commonFile2.path, ts.projectSystem.commonFile2.content); + host.writeFile(commonFile2.path, commonFile2.content); host.checkTimeoutQueueLengthAndRun(2); - ts.projectSystem.baselineTsserverLogs("configuredProjects", "add new files to a configured project without file list", projectService); + baselineTsserverLogs("configuredProjects", "add new files to a configured project without file list", projectService); }); it("should ignore non-existing files specified in the config file", () => { - const configFile: ts.projectSystem.File = { + const configFile: File = { path: "/a/b/tsconfig.json", content: `{ "compilerOptions": {}, @@ -126,83 +129,83 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { ] }` }; - const host = ts.projectSystem.createServerHost([ts.projectSystem.commonFile1, ts.projectSystem.commonFile2, configFile]); - const projectService = ts.projectSystem.createProjectService(host); - projectService.openClientFile(ts.projectSystem.commonFile1.path); - projectService.openClientFile(ts.projectSystem.commonFile2.path); + const host = createServerHost([commonFile1, commonFile2, configFile]); + const projectService = createProjectService(host); + projectService.openClientFile(commonFile1.path); + projectService.openClientFile(commonFile2.path); - ts.projectSystem.checkNumberOfConfiguredProjects(projectService, 1); - const project = ts.projectSystem.configuredProjectAt(projectService, 0); - ts.projectSystem.checkProjectRootFiles(project, [ts.projectSystem.commonFile1.path]); - ts.projectSystem.checkNumberOfInferredProjects(projectService, 1); + checkNumberOfConfiguredProjects(projectService, 1); + const project = configuredProjectAt(projectService, 0); + checkProjectRootFiles(project, [commonFile1.path]); + checkNumberOfInferredProjects(projectService, 1); }); it("handle recreated files correctly", () => { - const configFile: ts.projectSystem.File = { + const configFile: File = { path: "/a/b/tsconfig.json", content: `{}` }; - const host = ts.projectSystem.createServerHost([ts.projectSystem.commonFile1, ts.projectSystem.commonFile2, configFile]); - const projectService = ts.projectSystem.createProjectService(host); - projectService.openClientFile(ts.projectSystem.commonFile1.path); + const host = createServerHost([commonFile1, commonFile2, configFile]); + const projectService = createProjectService(host); + projectService.openClientFile(commonFile1.path); - ts.projectSystem.checkNumberOfConfiguredProjects(projectService, 1); - const project = ts.projectSystem.configuredProjectAt(projectService, 0); - ts.projectSystem.checkProjectRootFiles(project, [ts.projectSystem.commonFile1.path, ts.projectSystem.commonFile2.path]); + checkNumberOfConfiguredProjects(projectService, 1); + const project = configuredProjectAt(projectService, 0); + checkProjectRootFiles(project, [commonFile1.path, commonFile2.path]); // delete commonFile2 - host.deleteFile(ts.projectSystem.commonFile2.path); + host.deleteFile(commonFile2.path); host.checkTimeoutQueueLengthAndRun(2); - ts.projectSystem.checkProjectRootFiles(project, [ts.projectSystem.commonFile1.path]); + checkProjectRootFiles(project, [commonFile1.path]); // re-add commonFile2 - host.writeFile(ts.projectSystem.commonFile2.path, ts.projectSystem.commonFile2.content); + host.writeFile(commonFile2.path, commonFile2.content); host.checkTimeoutQueueLengthAndRun(2); - ts.projectSystem.checkProjectRootFiles(project, [ts.projectSystem.commonFile1.path, ts.projectSystem.commonFile2.path]); + checkProjectRootFiles(project, [commonFile1.path, commonFile2.path]); }); it("files explicitly excluded in config file", () => { - const configFile: ts.projectSystem.File = { + const configFile: File = { path: "/a/b/tsconfig.json", content: `{ "compilerOptions": {}, "exclude": ["/a/c"] }` }; - const excludedFile1: ts.projectSystem.File = { + const excludedFile1: File = { path: "/a/c/excluedFile1.ts", content: `let t = 1;` }; - const host = ts.projectSystem.createServerHost([ts.projectSystem.commonFile1, ts.projectSystem.commonFile2, excludedFile1, configFile]); - const projectService = ts.projectSystem.createProjectService(host); + const host = createServerHost([commonFile1, commonFile2, excludedFile1, configFile]); + const projectService = createProjectService(host); - projectService.openClientFile(ts.projectSystem.commonFile1.path); - ts.projectSystem.checkNumberOfConfiguredProjects(projectService, 1); - const project = ts.projectSystem.configuredProjectAt(projectService, 0); - ts.projectSystem.checkProjectRootFiles(project, [ts.projectSystem.commonFile1.path, ts.projectSystem.commonFile2.path]); + projectService.openClientFile(commonFile1.path); + checkNumberOfConfiguredProjects(projectService, 1); + const project = configuredProjectAt(projectService, 0); + checkProjectRootFiles(project, [commonFile1.path, commonFile2.path]); projectService.openClientFile(excludedFile1.path); - ts.projectSystem.checkNumberOfInferredProjects(projectService, 1); + checkNumberOfInferredProjects(projectService, 1); }); it("should properly handle module resolution changes in config file", () => { - const file1: ts.projectSystem.File = { + const file1: File = { path: "/a/b/file1.ts", content: `import { T } from "module1";` }; - const nodeModuleFile: ts.projectSystem.File = { + const nodeModuleFile: File = { path: "/a/b/node_modules/module1.ts", content: `export interface T {}` }; - const classicModuleFile: ts.projectSystem.File = { + const classicModuleFile: File = { path: "/a/module1.ts", content: `export interface T {}` }; - const randomFile: ts.projectSystem.File = { + const randomFile: File = { path: "/a/file1.ts", content: `export interface T {}` }; - const configFile: ts.projectSystem.File = { + const configFile: File = { path: "/a/b/tsconfig.json", content: `{ "compilerOptions": { @@ -212,17 +215,17 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { }` }; const files = [file1, nodeModuleFile, classicModuleFile, configFile, randomFile]; - const host = ts.projectSystem.createServerHost(files); - const projectService = ts.projectSystem.createProjectService(host); + const host = createServerHost(files); + const projectService = createProjectService(host); projectService.openClientFile(file1.path); projectService.openClientFile(nodeModuleFile.path); projectService.openClientFile(classicModuleFile.path); - ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 1 }); - const project = ts.projectSystem.configuredProjectAt(projectService, 0); + checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 1 }); + const project = configuredProjectAt(projectService, 0); const inferredProject0 = projectService.inferredProjects[0]; - ts.projectSystem.checkProjectActualFiles(project, [file1.path, nodeModuleFile.path, configFile.path]); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[0], [classicModuleFile.path]); + checkProjectActualFiles(project, [file1.path, nodeModuleFile.path, configFile.path]); + checkProjectActualFiles(projectService.inferredProjects[0], [classicModuleFile.path]); host.writeFile(configFile.path, `{ "compilerOptions": { @@ -232,33 +235,33 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { }`); host.checkTimeoutQueueLengthAndRun(2); - ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 2 }); // will not remove project 1 - ts.projectSystem.checkProjectActualFiles(project, [file1.path, classicModuleFile.path, configFile.path]); + checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 2 }); // will not remove project 1 + checkProjectActualFiles(project, [file1.path, classicModuleFile.path, configFile.path]); assert.strictEqual(projectService.inferredProjects[0], inferredProject0); assert.isTrue(projectService.inferredProjects[0].isOrphan()); const inferredProject1 = projectService.inferredProjects[1]; - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[1], [nodeModuleFile.path]); + checkProjectActualFiles(projectService.inferredProjects[1], [nodeModuleFile.path]); // Open random file and it will reuse first inferred project projectService.openClientFile(randomFile.path); - ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 2 }); - ts.projectSystem.checkProjectActualFiles(project, [file1.path, classicModuleFile.path, configFile.path]); + checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 2 }); + checkProjectActualFiles(project, [file1.path, classicModuleFile.path, configFile.path]); assert.strictEqual(projectService.inferredProjects[0], inferredProject0); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[0], [randomFile.path]); // Reuses first inferred project + checkProjectActualFiles(projectService.inferredProjects[0], [randomFile.path]); // Reuses first inferred project assert.strictEqual(projectService.inferredProjects[1], inferredProject1); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[1], [nodeModuleFile.path]); + checkProjectActualFiles(projectService.inferredProjects[1], [nodeModuleFile.path]); }); it("should keep the configured project when the opened file is referenced by the project but not its root", () => { - const file1: ts.projectSystem.File = { + const file1: File = { path: "/a/b/main.ts", content: "import { objA } from './obj-a';" }; - const file2: ts.projectSystem.File = { + const file2: File = { path: "/a/b/obj-a.ts", content: `export const objA = Object.assign({foo: "bar"}, {bar: "baz"});` }; - const configFile: ts.projectSystem.File = { + const configFile: File = { path: "/a/b/tsconfig.json", content: `{ "compilerOptions": { @@ -267,25 +270,25 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { "files": [ "main.ts" ] }` }; - const host = ts.projectSystem.createServerHost([file1, file2, configFile]); - const projectService = ts.projectSystem.createProjectService(host); + const host = createServerHost([file1, file2, configFile]); + const projectService = createProjectService(host); projectService.openClientFile(file1.path); projectService.closeClientFile(file1.path); projectService.openClientFile(file2.path); - ts.projectSystem.checkNumberOfConfiguredProjects(projectService, 1); - ts.projectSystem.checkNumberOfInferredProjects(projectService, 0); + checkNumberOfConfiguredProjects(projectService, 1); + checkNumberOfInferredProjects(projectService, 0); }); it("should keep the configured project when the opened file is referenced by the project but not its root", () => { - const file1: ts.projectSystem.File = { + const file1: File = { path: "/a/b/main.ts", content: "import { objA } from './obj-a';" }; - const file2: ts.projectSystem.File = { + const file2: File = { path: "/a/b/obj-a.ts", content: `export const objA = Object.assign({foo: "bar"}, {bar: "baz"});` }; - const configFile: ts.projectSystem.File = { + const configFile: File = { path: "/a/b/tsconfig.json", content: `{ "compilerOptions": { @@ -294,17 +297,17 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { "files": [ "main.ts" ] }` }; - const host = ts.projectSystem.createServerHost([file1, file2, configFile]); - const projectService = ts.projectSystem.createProjectService(host); + const host = createServerHost([file1, file2, configFile]); + const projectService = createProjectService(host); projectService.openClientFile(file1.path); projectService.closeClientFile(file1.path); projectService.openClientFile(file2.path); - ts.projectSystem.checkNumberOfConfiguredProjects(projectService, 1); - ts.projectSystem.checkNumberOfInferredProjects(projectService, 0); + checkNumberOfConfiguredProjects(projectService, 1); + checkNumberOfInferredProjects(projectService, 0); }); it("should tolerate config file errors and still try to build a project", () => { - const configFile: ts.projectSystem.File = { + const configFile: File = { path: "/a/b/tsconfig.json", content: `{ "compilerOptions": { @@ -314,11 +317,11 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { "someOtherProperty": {} }` }; - const host = ts.projectSystem.createServerHost([ts.projectSystem.commonFile1, ts.projectSystem.commonFile2, ts.projectSystem.libFile, configFile]); - const projectService = ts.projectSystem.createProjectService(host); - projectService.openClientFile(ts.projectSystem.commonFile1.path); - ts.projectSystem.checkNumberOfConfiguredProjects(projectService, 1); - ts.projectSystem.checkProjectRootFiles(ts.projectSystem.configuredProjectAt(projectService, 0), [ts.projectSystem.commonFile1.path, ts.projectSystem.commonFile2.path]); + const host = createServerHost([commonFile1, commonFile2, libFile, configFile]); + const projectService = createProjectService(host); + projectService.openClientFile(commonFile1.path); + checkNumberOfConfiguredProjects(projectService, 1); + checkProjectRootFiles(configuredProjectAt(projectService, 0), [commonFile1.path, commonFile2.path]); }); it("should reuse same project if file is opened from the configured project that has no open files", () => { @@ -330,7 +333,7 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { path: "/a/b/main2.ts", content: "let y =1;" }; - const configFile: ts.projectSystem.File = { + const configFile: File = { path: "/a/b/tsconfig.json", content: `{ "compilerOptions": { @@ -339,21 +342,21 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { "files": [ "main.ts", "main2.ts" ] }` }; - const host = ts.projectSystem.createServerHost([file1, file2, configFile, ts.projectSystem.libFile]); - const projectService = ts.projectSystem.createProjectService(host, { useSingleInferredProject: true }); + const host = createServerHost([file1, file2, configFile, libFile]); + const projectService = createProjectService(host, { useSingleInferredProject: true }); projectService.openClientFile(file1.path); - ts.projectSystem.checkNumberOfConfiguredProjects(projectService, 1); + checkNumberOfConfiguredProjects(projectService, 1); const project = projectService.configuredProjects.get(configFile.path)!; assert.isTrue(project.hasOpenRef()); // file1 projectService.closeClientFile(file1.path); - ts.projectSystem.checkNumberOfConfiguredProjects(projectService, 1); + checkNumberOfConfiguredProjects(projectService, 1); assert.strictEqual(projectService.configuredProjects.get(configFile.path), project); assert.isFalse(project.hasOpenRef()); // No open files assert.isFalse(project.isClosed()); projectService.openClientFile(file2.path); - ts.projectSystem.checkNumberOfConfiguredProjects(projectService, 1); + checkNumberOfConfiguredProjects(projectService, 1); assert.strictEqual(projectService.configuredProjects.get(configFile.path), project); assert.isTrue(project.hasOpenRef()); // file2 assert.isFalse(project.isClosed()); @@ -364,7 +367,7 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { path: "/a/b/main.ts", content: "let x =1;" }; - const configFile: ts.projectSystem.File = { + const configFile: File = { path: "/a/b/tsconfig.json", content: `{ "compilerOptions": { @@ -373,59 +376,59 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { "files": [ "main.ts" ] }` }; - const host = ts.projectSystem.createServerHost([file1, configFile, ts.projectSystem.libFile]); - const projectService = ts.projectSystem.createProjectService(host, { useSingleInferredProject: true }); + const host = createServerHost([file1, configFile, libFile]); + const projectService = createProjectService(host, { useSingleInferredProject: true }); projectService.openClientFile(file1.path); - ts.projectSystem.checkNumberOfConfiguredProjects(projectService, 1); + checkNumberOfConfiguredProjects(projectService, 1); const project = projectService.configuredProjects.get(configFile.path)!; assert.isTrue(project.hasOpenRef()); // file1 projectService.closeClientFile(file1.path); - ts.projectSystem.checkNumberOfConfiguredProjects(projectService, 1); + checkNumberOfConfiguredProjects(projectService, 1); assert.strictEqual(projectService.configuredProjects.get(configFile.path), project); assert.isFalse(project.hasOpenRef()); // No files assert.isFalse(project.isClosed()); - projectService.openClientFile(ts.projectSystem.libFile.path); - ts.projectSystem.checkNumberOfConfiguredProjects(projectService, 0); + projectService.openClientFile(libFile.path); + checkNumberOfConfiguredProjects(projectService, 0); assert.isFalse(project.hasOpenRef()); // No files + project closed assert.isTrue(project.isClosed()); }); it("open file become a part of configured project if it is referenced from root file", () => { const file1 = { - path: `${ts.tscWatch.projectRoot}/a/b/f1.ts`, + path: `/user/username/projects/myproject/a/b/f1.ts`, content: "export let x = 5" }; const file2 = { - path: `${ts.tscWatch.projectRoot}/a/c/f2.ts`, + path: `/user/username/projects/myproject/a/c/f2.ts`, content: `import {x} from "../b/f1"` }; const file3 = { - path: `${ts.tscWatch.projectRoot}/a/c/f3.ts`, + path: `/user/username/projects/myproject/a/c/f3.ts`, content: "export let y = 1" }; const configFile = { - path: `${ts.tscWatch.projectRoot}/a/c/tsconfig.json`, + path: `/user/username/projects/myproject/a/c/tsconfig.json`, content: JSON.stringify({ compilerOptions: {}, files: ["f2.ts", "f3.ts"] }) }; - 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.openClientFile(file1.path); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 1 }); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[0], [file1.path]); + checkNumberOfProjects(projectService, { inferredProjects: 1 }); + checkProjectActualFiles(projectService.inferredProjects[0], [file1.path]); projectService.openClientFile(file3.path); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 2 }); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[0], [file1.path]); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[1], [file3.path]); + checkNumberOfProjects(projectService, { inferredProjects: 2 }); + checkProjectActualFiles(projectService.inferredProjects[0], [file1.path]); + checkProjectActualFiles(projectService.inferredProjects[1], [file3.path]); host.writeFile(configFile.path, configFile.content); host.checkTimeoutQueueLengthAndRun(2); // load configured project from disk + ensureProjectsForOpenFiles - ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 2 }); - ts.projectSystem.checkProjectActualFiles(ts.projectSystem.configuredProjectAt(projectService, 0), [file1.path, file2.path, file3.path, configFile.path]); + checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 2 }); + checkProjectActualFiles(configuredProjectAt(projectService, 0), [file1.path, file2.path, file3.path, configFile.path]); assert.isTrue(projectService.inferredProjects[0].isOrphan()); assert.isTrue(projectService.inferredProjects[1].isOrphan()); }); @@ -444,19 +447,19 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { content: JSON.stringify({ compilerOptions: {} }) }; - 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 }); - ts.projectSystem.checkProjectActualFiles(ts.projectSystem.configuredProjectAt(projectService, 0), [file1.path, configFile.path]); + checkNumberOfProjects(projectService, { configuredProjects: 1 }); + checkProjectActualFiles(configuredProjectAt(projectService, 0), [file1.path, configFile.path]); host.writeFile(file2.path, file2.content); host.checkTimeoutQueueLengthAndRun(2); - ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 }); - ts.projectSystem.checkProjectRootFiles(ts.projectSystem.configuredProjectAt(projectService, 0), [file1.path, file2.path]); + checkNumberOfProjects(projectService, { configuredProjects: 1 }); + checkProjectRootFiles(configuredProjectAt(projectService, 0), [file1.path, file2.path]); }); it("can correctly update configured project when set of root files has changed (new file in list of files)", () => { @@ -473,18 +476,18 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { content: JSON.stringify({ compilerOptions: {}, files: ["f1.ts"] }) }; - const host = ts.projectSystem.createServerHost([file1, file2, configFile]); - const projectService = ts.projectSystem.createProjectService(host); + const host = createServerHost([file1, file2, configFile]); + const projectService = createProjectService(host); projectService.openClientFile(file1.path); - ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 }); - ts.projectSystem.checkProjectActualFiles(ts.projectSystem.configuredProjectAt(projectService, 0), [file1.path, configFile.path]); + checkNumberOfProjects(projectService, { configuredProjects: 1 }); + checkProjectActualFiles(configuredProjectAt(projectService, 0), [file1.path, configFile.path]); host.writeFile(configFile.path, JSON.stringify({ compilerOptions: {}, files: ["f1.ts", "f2.ts"] })); - ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 }); + checkNumberOfProjects(projectService, { configuredProjects: 1 }); host.checkTimeoutQueueLengthAndRun(2); - ts.projectSystem.checkProjectRootFiles(ts.projectSystem.configuredProjectAt(projectService, 0), [file1.path, file2.path]); + checkProjectRootFiles(configuredProjectAt(projectService, 0), [file1.path, file2.path]); }); it("can update configured project when set of root files was not changed", () => { @@ -501,33 +504,33 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { content: JSON.stringify({ compilerOptions: {}, files: ["f1.ts", "f2.ts"] }) }; - const host = ts.projectSystem.createServerHost([file1, file2, configFile]); - const projectService = ts.projectSystem.createProjectService(host); + const host = createServerHost([file1, file2, configFile]); + const projectService = createProjectService(host); projectService.openClientFile(file1.path); - ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 }); - ts.projectSystem.checkProjectActualFiles(ts.projectSystem.configuredProjectAt(projectService, 0), [file1.path, file2.path, configFile.path]); + checkNumberOfProjects(projectService, { configuredProjects: 1 }); + checkProjectActualFiles(configuredProjectAt(projectService, 0), [file1.path, file2.path, configFile.path]); host.writeFile(configFile.path, JSON.stringify({ compilerOptions: { outFile: "out.js" }, files: ["f1.ts", "f2.ts"] })); - ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 }); - ts.projectSystem.checkProjectRootFiles(ts.projectSystem.configuredProjectAt(projectService, 0), [file1.path, file2.path]); + checkNumberOfProjects(projectService, { configuredProjects: 1 }); + checkProjectRootFiles(configuredProjectAt(projectService, 0), [file1.path, file2.path]); }); it("Open ref of configured project when open file gets added to the project as part of configured file update", () => { - const file1: ts.projectSystem.File = { + const file1: File = { path: "/a/b/src/file1.ts", content: "let x = 1;" }; - const file2: ts.projectSystem.File = { + const file2: File = { path: "/a/b/src/file2.ts", content: "let y = 1;" }; - const file3: ts.projectSystem.File = { + const file3: File = { path: "/a/b/file3.ts", content: "let z = 1;" }; - const file4: ts.projectSystem.File = { + const file4: File = { path: "/a/file4.ts", content: "let z = 1;" }; @@ -537,8 +540,8 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { }; const files = [file1, file2, file3, file4]; - const host = ts.projectSystem.createServerHost(files.concat(configFile)); - const projectService = ts.projectSystem.createProjectService(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); + const host = createServerHost(files.concat(configFile)); + const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); projectService.openClientFile(file1.path); projectService.openClientFile(file2.path); @@ -565,15 +568,15 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { projectService.openClientFile(file4.path); assert.isTrue(configProject1.hasOpenRef()); // file3 const inferredProject4 = projectService.inferredProjects[0]; - ts.projectSystem.checkProjectActualFiles(inferredProject4, [file4.path]); + checkProjectActualFiles(inferredProject4, [file4.path]); projectService.closeClientFile(file3.path); assert.isFalse(configProject1.hasOpenRef()); // No open files const inferredProject5 = projectService.inferredProjects[0]; - ts.projectSystem.checkProjectActualFiles(inferredProject4, [file4.path]); + checkProjectActualFiles(inferredProject4, [file4.path]); assert.strictEqual(inferredProject5, inferredProject4); - const file5: ts.projectSystem.File = { + const file5: File = { path: "/file5.ts", content: "let zz = 1;" }; @@ -581,23 +584,23 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { projectService.testhost.baselineHost("File5 written"); projectService.openClientFile(file5.path); - ts.projectSystem.baselineTsserverLogs("configuredProjects", "Open ref of configured project when open file gets added to the project as part of configured file update", projectService); + baselineTsserverLogs("configuredProjects", "Open ref of configured project when open file gets added to the project as part of configured file update", projectService); }); it("Open ref of configured project when open file gets added to the project as part of configured file update buts its open file references are all closed when the update happens", () => { - const file1: ts.projectSystem.File = { + const file1: File = { path: "/a/b/src/file1.ts", content: "let x = 1;" }; - const file2: ts.projectSystem.File = { + const file2: File = { path: "/a/b/src/file2.ts", content: "let y = 1;" }; - const file3: ts.projectSystem.File = { + const file3: File = { path: "/a/b/file3.ts", content: "let z = 1;" }; - const file4: ts.projectSystem.File = { + const file4: File = { path: "/a/file4.ts", content: "let z = 1;" }; @@ -608,19 +611,19 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { const files = [file1, file2, file3]; const hostFiles = files.concat(file4, configFile); - const host = ts.projectSystem.createServerHost(hostFiles); - const projectService = ts.projectSystem.createProjectService(host); + const host = createServerHost(hostFiles); + const projectService = createProjectService(host); projectService.openClientFile(file1.path); projectService.openClientFile(file2.path); projectService.openClientFile(file3.path); - ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 1 }); + checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 1 }); const configuredProject = projectService.configuredProjects.get(configFile.path)!; assert.isTrue(configuredProject.hasOpenRef()); // file1 and file3 - ts.projectSystem.checkProjectActualFiles(configuredProject, [file1.path, file3.path, configFile.path]); + checkProjectActualFiles(configuredProject, [file1.path, file3.path, configFile.path]); const inferredProject1 = projectService.inferredProjects[0]; - ts.projectSystem.checkProjectActualFiles(inferredProject1, [file2.path]); + checkProjectActualFiles(inferredProject1, [file2.path]); projectService.closeClientFile(file1.path); projectService.closeClientFile(file3.path); @@ -632,22 +635,22 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { projectService.openClientFile(file4.path); - ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 2 }); + checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 2 }); assert.strictEqual(projectService.configuredProjects.get(configFile.path), configuredProject); assert.isTrue(configuredProject.hasOpenRef()); // Pending update and F2 might get into the project assert.strictEqual(projectService.inferredProjects[0], inferredProject1); const inferredProject2 = projectService.inferredProjects[1]; - ts.projectSystem.checkProjectActualFiles(inferredProject2, [file4.path]); + checkProjectActualFiles(inferredProject2, [file4.path]); host.runQueuedTimeoutCallbacks(); - ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 2 }); + checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 2 }); assert.strictEqual(projectService.configuredProjects.get(configFile.path), configuredProject); assert.isTrue(configuredProject.hasOpenRef()); // file2 - ts.projectSystem.checkProjectActualFiles(configuredProject, [file1.path, file2.path, file3.path, configFile.path]); + checkProjectActualFiles(configuredProject, [file1.path, file2.path, file3.path, configFile.path]); assert.strictEqual(projectService.inferredProjects[0], inferredProject1); assert.isTrue(inferredProject1.isOrphan()); assert.strictEqual(projectService.inferredProjects[1], inferredProject2); - ts.projectSystem.checkProjectActualFiles(inferredProject2, [file4.path]); + checkProjectActualFiles(inferredProject2, [file4.path]); }); it("files are properly detached when language service is disabled", () => { @@ -667,12 +670,12 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { path: "/a/tsconfig.json", content: JSON.stringify({ compilerOptions: { allowJs: true } }) }; - const host = ts.projectSystem.createServerHost([f1, f2, f3, config]); + const host = createServerHost([f1, f2, f3, config]); const originalGetFileSize = host.getFileSize; host.getFileSize = (filePath: string) => filePath === f2.path ? ts.server.maxProgramSizeForNonTsFiles + 1 : originalGetFileSize.call(host, filePath); - const projectService = ts.projectSystem.createProjectService(host); + const projectService = createProjectService(host); projectService.openClientFile(f1.path); projectService.checkNumberOfProjects({ configuredProjects: 1 }); const project = projectService.configuredProjects.get(config.path)!; @@ -721,21 +724,21 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { path: "/a/jsconfig.json", content: "{}" }; - 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(host, ts.server.ProjectLanguageServiceStateEvent); + const { session, events } = createSessionWithEventTracking(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"); @@ -747,8 +750,8 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { }); it("when multiple projects are open, detects correct default project", () => { - const barConfig: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/bar/tsconfig.json`, + const barConfig: File = { + path: `/user/username/projects/myproject/bar/tsconfig.json`, content: JSON.stringify({ include: ["index.ts"], compilerOptions: { @@ -756,15 +759,15 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { } }) }; - const barIndex: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/bar/index.ts`, + const barIndex: File = { + path: `/user/username/projects/myproject/bar/index.ts`, content: ` export function bar() { console.log("hello world"); }` }; - const fooConfig: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/foo/tsconfig.json`, + const fooConfig: File = { + path: `/user/username/projects/myproject/foo/tsconfig.json`, content: JSON.stringify({ include: ["index.ts"], compilerOptions: { @@ -772,75 +775,75 @@ export function bar() { } }) }; - const fooIndex: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/foo/index.ts`, + const fooIndex: File = { + path: `/user/username/projects/myproject/foo/index.ts`, content: ` import { bar } from "bar"; bar();` }; - const barSymLink: ts.projectSystem.SymLink = { - path: `${ts.tscWatch.projectRoot}/foo/node_modules/bar`, - symLink: `${ts.tscWatch.projectRoot}/bar` + const barSymLink: SymLink = { + path: `/user/username/projects/myproject/foo/node_modules/bar`, + symLink: `/user/username/projects/myproject/bar` }; - const lib2017: ts.projectSystem.File = { - path: `${ts.getDirectoryPath(ts.projectSystem.libFile.path)}/lib.es2017.d.ts`, - content: ts.projectSystem.libFile.content + const lib2017: File = { + path: `${ts.getDirectoryPath(libFile.path)}/lib.es2017.d.ts`, + content: libFile.content }; - const libDom: ts.projectSystem.File = { - path: `${ts.getDirectoryPath(ts.projectSystem.libFile.path)}/lib.dom.d.ts`, + const libDom: File = { + path: `${ts.getDirectoryPath(libFile.path)}/lib.dom.d.ts`, content: ` declare var console: { log(...args: any[]): void; };` }; - const host = ts.projectSystem.createServerHost([barConfig, barIndex, fooConfig, fooIndex, barSymLink, lib2017, libDom]); - const session = ts.projectSystem.createSession(host, { canUseEvents: true, logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([fooIndex, barIndex], session); - ts.projectSystem.verifyGetErrRequest({ session, host, files: [barIndex, fooIndex] }); - ts.projectSystem.baselineTsserverLogs("configuredProjects", "when multiple projects are open detects correct default project", session); + const host = createServerHost([barConfig, barIndex, fooConfig, fooIndex, barSymLink, lib2017, libDom]); + const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([fooIndex, barIndex], session); + verifyGetErrRequest({ session, host, files: [barIndex, fooIndex] }); + baselineTsserverLogs("configuredProjects", "when multiple projects are open detects correct default project", session); }); 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 tsconfig: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/tsconfig.json`, + const tsconfig: File = { + path: `/user/username/projects/myproject/tsconfig.json`, content: "{}" }; - const host = ts.projectSystem.createServerHost([file, app, tsconfig, ts.projectSystem.libFile]); - const service = ts.projectSystem.createProjectService(host); + const host = createServerHost([file, app, tsconfig, libFile]); + const service = createProjectService(host); service.openClientFile(file.path); }); describe("when creating new file", () => { - const foo: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/src/foo.ts`, + const foo: File = { + path: `/user/username/projects/myproject/src/foo.ts`, content: "export function foo() { }" }; - const bar: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/src/bar.ts`, + const bar: File = { + path: `/user/username/projects/myproject/src/bar.ts`, content: "export function bar() { }" }; - const config: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/tsconfig.json`, + const config: File = { + path: `/user/username/projects/myproject/tsconfig.json`, content: JSON.stringify({ include: ["./src"] }) }; - const fooBar: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/src/sub/fooBar.ts`, + const fooBar: File = { + path: `/user/username/projects/myproject/src/sub/fooBar.ts`, content: "export function fooBar() { }" }; function verifySessionWorker({ withExclude, openFileBeforeCreating }: VerifySession, errorOnNewFileBeforeOldFile: boolean) { - const host = ts.projectSystem.createServerHost([ - foo, bar, ts.projectSystem.libFile, { path: `${ts.tscWatch.projectRoot}/src/sub` }, + const host = createServerHost([ + foo, bar, libFile, { path: `/user/username/projects/myproject/src/sub` }, withExclude ? { path: config.path, @@ -851,33 +854,33 @@ declare var console: { } : config ]); - const session = ts.projectSystem.createSession(host, { + const session = createSession(host, { canUseEvents: true, - logger: ts.projectSystem.createLoggerWithInMemoryLogs(host), + logger: createLoggerWithInMemoryLogs(host), }); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Open, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Open, arguments: { file: foo.path, fileContent: foo.content, - projectRootPath: ts.tscWatch.projectRoot + projectRootPath: "/user/username/projects/myproject" } }); if (!openFileBeforeCreating) { host.writeFile(fooBar.path, fooBar.content); } - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Open, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Open, arguments: { file: fooBar.path, fileContent: fooBar.content, - projectRootPath: ts.tscWatch.projectRoot + projectRootPath: "/user/username/projects/myproject" } }); if (openFileBeforeCreating) { host.writeFile(fooBar.path, fooBar.content); } - ts.projectSystem.verifyGetErrRequest({ + verifyGetErrRequest({ session, host, files: errorOnNewFileBeforeOldFile ? @@ -885,7 +888,7 @@ declare var console: { [foo, fooBar], existingTimeouts: withExclude ? 0 : 2 }); - ts.projectSystem.baselineTsserverLogs("configuredProjects", `creating new file and then open it ${openFileBeforeCreating ? "before" : "after"} watcher is invoked, ask errors on it ${errorOnNewFileBeforeOldFile ? "before" : "after"} old one${withExclude ? " without file being in config" : ""}`, session); + baselineTsserverLogs("configuredProjects", `creating new file and then open it ${openFileBeforeCreating ? "before" : "after"} watcher is invoked, ask errors on it ${errorOnNewFileBeforeOldFile ? "before" : "after"} old one${withExclude ? " without file being in config" : ""}`, session); } interface VerifySession { withExclude?: boolean; @@ -926,25 +929,25 @@ declare var console: { }); it("when default configured project does not contain the file", () => { - const barConfig: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/bar/tsconfig.json`, + const barConfig: File = { + path: `/user/username/projects/myproject/bar/tsconfig.json`, content: "{}" }; - const barIndex: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/bar/index.ts`, + const barIndex: File = { + path: `/user/username/projects/myproject/bar/index.ts`, content: `import {foo} from "../foo/lib"; foo();` }; - const fooBarConfig: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/foobar/tsconfig.json`, + const fooBarConfig: File = { + path: `/user/username/projects/myproject/foobar/tsconfig.json`, content: barConfig.path }; - const fooBarIndex: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/foobar/index.ts`, + const fooBarIndex: File = { + path: `/user/username/projects/myproject/foobar/index.ts`, content: barIndex.content }; - const fooConfig: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/foo/tsconfig.json`, + const fooConfig: File = { + path: `/user/username/projects/myproject/foo/tsconfig.json`, content: JSON.stringify({ include: ["index.ts"], compilerOptions: { @@ -953,25 +956,25 @@ foo();` } }) }; - const fooIndex: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/foo/index.ts`, + const fooIndex: File = { + path: `/user/username/projects/myproject/foo/index.ts`, content: `export function foo() {}` }; - const host = ts.projectSystem.createServerHost([barConfig, barIndex, fooBarConfig, fooBarIndex, fooConfig, fooIndex, ts.projectSystem.libFile]); - ts.tscWatch.ensureErrorFreeBuild(host, [fooConfig.path]); - const fooDts = `${ts.tscWatch.projectRoot}/foo/lib/index.d.ts`; + const host = createServerHost([barConfig, barIndex, fooBarConfig, fooBarIndex, fooConfig, fooIndex, libFile]); + ensureErrorFreeBuild(host, [fooConfig.path]); + const fooDts = `/user/username/projects/myproject/foo/lib/index.d.ts`; assert.isTrue(host.fileExists(fooDts)); - const session = ts.projectSystem.createSession(host); + const session = createSession(host); const service = session.getProjectService(); service.openClientFile(barIndex.path); - ts.projectSystem.checkProjectActualFiles(service.configuredProjects.get(barConfig.path)!, [barIndex.path, fooDts, ts.projectSystem.libFile.path, barConfig.path]); + checkProjectActualFiles(service.configuredProjects.get(barConfig.path)!, [barIndex.path, fooDts, libFile.path, barConfig.path]); service.openClientFile(fooBarIndex.path); - ts.projectSystem.checkProjectActualFiles(service.configuredProjects.get(fooBarConfig.path)!, [fooBarIndex.path, fooDts, ts.projectSystem.libFile.path, fooBarConfig.path]); + checkProjectActualFiles(service.configuredProjects.get(fooBarConfig.path)!, [fooBarIndex.path, fooDts, libFile.path, fooBarConfig.path]); service.openClientFile(fooIndex.path); - ts.projectSystem.checkProjectActualFiles(service.configuredProjects.get(fooConfig.path)!, [fooIndex.path, ts.projectSystem.libFile.path, fooConfig.path]); + checkProjectActualFiles(service.configuredProjects.get(fooConfig.path)!, [fooIndex.path, libFile.path, fooConfig.path]); service.openClientFile(fooDts); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.GetApplicableRefactors, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.GetApplicableRefactors, arguments: { file: fooDts, startLine: 1, @@ -984,42 +987,42 @@ foo();` }); describe("watches extended config files", () => { - function getService(additionalFiles?: ts.projectSystem.File[]) { - const alphaExtendedConfig: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/extended/alpha.tsconfig.json`, + function getService(additionalFiles?: File[]) { + const alphaExtendedConfig: File = { + path: `/user/username/projects/myproject/extended/alpha.tsconfig.json`, content: "{}" }; - const bravoExtendedConfig: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/extended/bravo.tsconfig.json`, + const bravoExtendedConfig: File = { + path: `/user/username/projects/myproject/extended/bravo.tsconfig.json`, content: JSON.stringify({ extends: "./alpha.tsconfig.json" }) }; - const aConfig: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/a/tsconfig.json`, + const aConfig: File = { + path: `/user/username/projects/myproject/a/tsconfig.json`, content: JSON.stringify({ extends: "../extended/alpha.tsconfig.json", files: ["a.ts"] }) }; - const aFile: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/a/a.ts`, + const aFile: File = { + path: `/user/username/projects/myproject/a/a.ts`, content: `let a = 1;` }; - const bConfig: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/b/tsconfig.json`, + const bConfig: File = { + path: `/user/username/projects/myproject/b/tsconfig.json`, content: JSON.stringify({ extends: "../extended/bravo.tsconfig.json", files: ["b.ts"] }) }; - const bFile: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/b/b.ts`, + const bFile: File = { + path: `/user/username/projects/myproject/b/b.ts`, content: `let b = 1;` }; - const host = ts.projectSystem.createServerHost([alphaExtendedConfig, aConfig, aFile, bravoExtendedConfig, bConfig, bFile, ...(additionalFiles || ts.emptyArray)]); - const projectService = ts.projectSystem.createProjectService(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); + const host = createServerHost([alphaExtendedConfig, aConfig, aFile, bravoExtendedConfig, bConfig, bFile, ...(additionalFiles || ts.emptyArray)]); + const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); return { host, projectService, aFile, bFile, aConfig, bConfig, alphaExtendedConfig, bravoExtendedConfig }; } @@ -1051,16 +1054,16 @@ foo();` host.writeFile(alphaExtendedConfig.path, "{}"); host.checkTimeoutQueueLengthAndRun(3); - ts.projectSystem.baselineTsserverLogs("configuredProjects", "should watch the extended configs of multiple projects", projectService); + baselineTsserverLogs("configuredProjects", "should watch the extended configs of multiple projects", projectService); }); it("should stop watching the extended configs of closed projects", () => { - const dummy: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/dummy/dummy.ts`, + const dummy: File = { + path: `/user/username/projects/myproject/dummy/dummy.ts`, content: `let dummy = 1;` }; - const dummyConfig: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/dummy/tsconfig.json`, + const dummyConfig: File = { + path: `/user/username/projects/myproject/dummy/tsconfig.json`, content: "{}" }; const { projectService, aFile, bFile } = getService([dummy, dummyConfig]); @@ -1077,7 +1080,7 @@ foo();` projectService.closeClientFile(aFile.path); projectService.closeClientFile(dummy.path); projectService.openClientFile(dummy.path); - ts.projectSystem.baselineTsserverLogs("configuredProjects", "should stop watching the extended configs of closed projects", projectService); + baselineTsserverLogs("configuredProjects", "should stop watching the extended configs of closed projects", projectService); }); }); }); @@ -1096,13 +1099,13 @@ describe("unittests:: tsserver:: ConfiguredProjects:: non-existing directories l content: "let t = 10;" }; - 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); host.runQueuedTimeoutCallbacks(); // Since file1 refers to config file as the default project, it needs to be kept alive - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 1, configuredProjects: 1 }); + checkNumberOfProjects(projectService, { inferredProjects: 1, configuredProjects: 1 }); const inferredProject = projectService.inferredProjects[0]; assert.isTrue(inferredProject.containsFile(file1.path as ts.server.NormalizedPath)); assert.isFalse(projectService.configuredProjects.get(configFile.path)!.containsFile(file1.path as ts.server.NormalizedPath)); @@ -1128,8 +1131,8 @@ describe("unittests:: tsserver:: ConfiguredProjects:: non-existing directories l path: "/a/node_modules/@types/typings/lib.d.ts", content: `export const x: number` }; - const host = ts.projectSystem.createServerHost([f, config, t1, t2], { currentDirectory: ts.getDirectoryPath(f.path) }); - const projectService = ts.projectSystem.createProjectService(host); + const host = createServerHost([f, config, t1, t2], { currentDirectory: ts.getDirectoryPath(f.path) }); + const projectService = createProjectService(host); projectService.openClientFile(f.path); // Since f refers to config file as the default project, it needs to be kept alive @@ -1138,11 +1141,11 @@ describe("unittests:: tsserver:: ConfiguredProjects:: non-existing directories l it("should tolerate invalid include files that start in subDirectory", () => { const f = { - path: `${ts.tscWatch.projectRoot}/src/server/index.ts`, + path: `/user/username/projects/myproject/src/server/index.ts`, content: "let x = 1" }; const config = { - path: `${ts.tscWatch.projectRoot}/src/server/tsconfig.json`, + path: `/user/username/projects/myproject/src/server/tsconfig.json`, content: JSON.stringify({ compiler: { module: "commonjs", @@ -1153,8 +1156,8 @@ describe("unittests:: tsserver:: ConfiguredProjects:: non-existing directories l ] }) }; - const host = ts.projectSystem.createServerHost([f, config, ts.projectSystem.libFile], { useCaseSensitiveFileNames: true }); - const projectService = ts.projectSystem.createProjectService(host); + const host = createServerHost([f, config, libFile], { useCaseSensitiveFileNames: true }); + const projectService = createProjectService(host); projectService.openClientFile(f.path); // Since f refers to config file as the default project, it needs to be kept alive @@ -1162,25 +1165,25 @@ describe("unittests:: tsserver:: ConfiguredProjects:: non-existing directories l }); it("Changed module resolution reflected when specifying files list", () => { - const file1: ts.projectSystem.File = { + const file1: File = { path: "/a/b/file1.ts", content: 'import classc from "file2"' }; - const file2a: ts.projectSystem.File = { + const file2a: File = { path: "/a/file2.ts", content: "export classc { method2a() { return 10; } }" }; - const file2: ts.projectSystem.File = { + const file2: File = { path: "/a/b/file2.ts", content: "export classc { method2() { return 10; } }" }; - const configFile: ts.projectSystem.File = { + const configFile: File = { path: "/a/b/tsconfig.json", content: JSON.stringify({ files: [file1.path], compilerOptions: { module: "amd" } }) }; - const files = [file1, file2a, configFile, ts.projectSystem.libFile]; - const host = ts.projectSystem.createServerHost(files); - const projectService = ts.projectSystem.createProjectService(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); + const files = [file1, file2a, configFile, libFile]; + const host = createServerHost(files); + const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); projectService.openClientFile(file1.path); host.writeFile(file2.path, file2.content); @@ -1189,62 +1192,62 @@ describe("unittests:: tsserver:: ConfiguredProjects:: non-existing directories l // On next file open the files file2a should be closed and not watched any more projectService.openClientFile(file2.path); - ts.projectSystem.baselineTsserverLogs("configuredProjects", "changed module resolution reflected when specifying files list", projectService); + baselineTsserverLogs("configuredProjects", "changed module resolution reflected when specifying files list", projectService); }); it("Failed lookup locations uses parent most node_modules directory", () => { const root = "/user/username/rootfolder"; - const file1: ts.projectSystem.File = { + const file1: File = { path: "/a/b/src/file1.ts", content: 'import { classc } from "module1"' }; - const module1: ts.projectSystem.File = { + const module1: File = { path: "/a/b/node_modules/module1/index.d.ts", content: `import { class2 } from "module2"; export classc { method2a(): class2; }` }; - const module2: ts.projectSystem.File = { + const module2: File = { path: "/a/b/node_modules/module2/index.d.ts", content: "export class2 { method2() { return 10; } }" }; - const module3: ts.projectSystem.File = { + const module3: File = { path: "/a/b/node_modules/module/node_modules/module3/index.d.ts", content: "export class3 { method2() { return 10; } }" }; - const configFile: ts.projectSystem.File = { + const configFile: File = { path: "/a/b/src/tsconfig.json", content: JSON.stringify({ files: ["file1.ts"] }) }; const nonLibFiles = [file1, module1, module2, module3, configFile]; nonLibFiles.forEach(f => f.path = root + f.path); - const files = nonLibFiles.concat(ts.projectSystem.libFile); - const host = ts.projectSystem.createServerHost(files); - const projectService = ts.projectSystem.createProjectService(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); + const files = nonLibFiles.concat(libFile); + const host = createServerHost(files); + const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); projectService.openClientFile(file1.path); - ts.projectSystem.baselineTsserverLogs("configuredProjects", "failed lookup locations uses parent most node_modules directory", projectService); + baselineTsserverLogs("configuredProjects", "failed lookup locations uses parent most node_modules directory", projectService); }); }); describe("unittests:: tsserver:: ConfiguredProjects:: when reading tsconfig file fails", () => { it("should be tolerated without crashing the server", () => { const configFile = { - path: `${ts.tscWatch.projectRoot}/tsconfig.json`, + path: `/user/username/projects/myproject/tsconfig.json`, content: "" }; const file1 = { - path: `${ts.tscWatch.projectRoot}/file1.ts`, + path: `/user/username/projects/myproject/file1.ts`, content: "let t = 10;" }; - const host = ts.projectSystem.createServerHost([file1, ts.projectSystem.libFile, configFile]); - const { session, events } = ts.projectSystem.createSessionWithEventTracking(host, ts.server.ConfigFileDiagEvent); + const host = createServerHost([file1, libFile, configFile]); + const { session, events } = createSessionWithEventTracking(host, ts.server.ConfigFileDiagEvent); const originalReadFile = host.readFile; host.readFile = f => { return f === configFile.path ? undefined : originalReadFile.call(host, f); }; - ts.projectSystem.openFilesForSession([file1], session); + openFilesForSession([file1], session); assert.deepEqual(events, [{ eventName: ts.server.ConfigFileDiagEvent, diff --git a/src/testRunner/unittests/tsserver/declarationFileMaps.ts b/src/testRunner/unittests/tsserver/declarationFileMaps.ts index ccc6b962637..5f98d88ecdd 100644 --- a/src/testRunner/unittests/tsserver/declarationFileMaps.ts +++ b/src/testRunner/unittests/tsserver/declarationFileMaps.ts @@ -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(session, ts.projectSystem.protocol.CommandTypes.Definition, ts.projectSystem.protocolFileLocationFromSubstring(userTs, "fnA()")); + const response = executeSessionRequest(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(session, ts.projectSystem.protocol.CommandTypes.DefinitionAndBoundSpan, ts.projectSystem.protocolFileLocationFromSubstring(userTs, "fnA()")); + const response = executeSessionRequest(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(session, ts.projectSystem.protocol.CommandTypes.DefinitionAndBoundSpan, ts.projectSystem.protocolFileLocationFromSubstring(userTs, "fnA()")); + const response = executeSessionRequest(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(session, ts.projectSystem.protocol.CommandTypes.TypeDefinition, ts.projectSystem.protocolFileLocationFromSubstring(userTs, "instanceA")); + const response = executeSessionRequest(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(session, ts.projectSystem.protocol.CommandTypes.Implementation, ts.projectSystem.protocolFileLocationFromSubstring(userTs, "fnA()")); + const response = executeSessionRequest(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(session, ts.projectSystem.CommandNames.Definition, ts.projectSystem.protocolFileLocationFromSubstring(userTs, "fnB()")); + const response = executeSessionRequest(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(session, ts.projectSystem.CommandNames.Navto, { file: userTs.path, searchValue: "fn" }); - assert.deepEqual(response, [ + const response = executeSessionRequest(session, ts.server.CommandNames.Navto, { file: userTs.path, searchValue: "fn" }); + assert.deepEqual(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(session, ts.projectSystem.CommandNames.Navto, { file: undefined, searchValue: "fn" }); - assert.deepEqual(response, [ + const response = executeSessionRequest(session, ts.server.CommandNames.Navto, { file: undefined, searchValue: "fn" }); + assert.deepEqual(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(session, ts.projectSystem.CommandNames.Navto, { projectFileName: bTsconfig.path, file: undefined, searchValue: "fn" }); - assert.deepEqual(response, [ + const response = executeSessionRequest(session, ts.server.CommandNames.Navto, { projectFileName: bTsconfig.path, file: undefined, searchValue: "fn" }); + assert.deepEqual(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(session, ts.projectSystem.protocol.CommandTypes.References, ts.projectSystem.protocolFileLocationFromSubstring(userTs, "fnA()")); - assert.deepEqual(response, { + const response = executeSessionRequest(session, ts.server.protocol.CommandTypes.References, protocolFileLocationFromSubstring(userTs, "fnA()")); + assert.deepEqual(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(session, ts.projectSystem.protocol.CommandTypes.References, ts.projectSystem.protocolFileLocationFromSubstring(aTs, "fnA")); - assert.deepEqual(response, { + openFilesForSession([aTs], session); // If it's not opened, the reference isn't found. + const response = executeSessionRequest(session, ts.server.protocol.CommandTypes.References, protocolFileLocationFromSubstring(aTs, "fnA")); + assert.deepEqual(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(session, ts.projectSystem.protocol.CommandTypes.ReferencesFull, ts.projectSystem.protocolFileLocationFromSubstring(userTs, "fnA()")); + const responseFull = executeSessionRequest(session, ts.server.protocol.CommandTypes.ReferencesFull, protocolFileLocationFromSubstring(userTs, "fnA()")); assert.deepEqual(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(session, ts.projectSystem.protocol.CommandTypes.ReferencesFull, ts.projectSystem.protocolFileLocationFromSubstring(bTs, "f()")); + const responseFull = executeSessionRequest(session, ts.server.protocol.CommandTypes.ReferencesFull, protocolFileLocationFromSubstring(bTs, "f()")); assert.deepEqual(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(session, ts.projectSystem.protocol.CommandTypes.References, ts.projectSystem.protocolFileLocationFromSubstring(userTs, "fnB()")); - assert.deepEqual(response, { + const response = executeSessionRequest(session, ts.server.protocol.CommandTypes.References, protocolFileLocationFromSubstring(userTs, "fnB()")); + assert.deepEqual(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(session, ts.projectSystem.protocol.CommandTypes.Rename, ts.projectSystem.protocolFileLocationFromSubstring(userTs, "fnA()")); - assert.deepEqual(response, { + const response = executeSessionRequest(session, ts.server.protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(userTs, "fnA()")); + assert.deepEqual(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(session, ts.projectSystem.protocol.CommandTypes.Rename, ts.projectSystem.protocolFileLocationFromSubstring(aTs, "fnA")); - assert.deepEqual(response, { + openFilesForSession([aTs], session); // If it's not opened, the reference isn't found. + const response = executeSessionRequest(session, ts.server.protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(aTs, "fnA")); + assert.deepEqual(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(session, ts.projectSystem.protocol.CommandTypes.RenameLocationsFull, ts.projectSystem.protocolFileLocationFromSubstring(userTs, "fnA()")); + const response = executeSessionRequest(session, ts.server.protocol.CommandTypes.RenameLocationsFull, protocolFileLocationFromSubstring(userTs, "fnA()")); assert.deepEqual(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(session, ts.projectSystem.protocol.CommandTypes.Rename, ts.projectSystem.protocolFileLocationFromSubstring(userTs, "fnB()")); - assert.deepEqual(response, { + const response = executeSessionRequest(session, ts.server.protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(userTs, "fnB()")); + assert.deepEqual(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(session, ts.projectSystem.protocol.CommandTypes.GetEditsForFileRename, { + const response = executeSessionRequest(session, ts.server.protocol.CommandTypes.GetEditsForFileRename, { oldFilePath: aTs.path, newFilePath: "/a/aNew.ts", }); - assert.deepEqual(response, [ + assert.deepEqual(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(session, ts.projectSystem.CommandNames.GetEditsForFileRename, { + const host = createServerHost([aTs, aTsconfig, bTs, bTsconfig]); + const session = createSession(host); + openFilesForSession([aTs, bTs], session); + const response = executeSessionRequest(session, ts.server.CommandNames.GetEditsForFileRename, { oldFilePath: aTs.path, newFilePath: "/a/src/a1.ts", }); - assert.deepEqual(response, []); // Should not change anything + assert.deepEqual(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( + executeSessionRequest( 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( + executeSessionRequest( 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() {}" diff --git a/src/testRunner/unittests/tsserver/documentRegistry.ts b/src/testRunner/unittests/tsserver/documentRegistry.ts index fbb291a738a..304e0b78f5a 100644 --- a/src/testRunner/unittests/tsserver/documentRegistry.ts +++ b/src/testRunner/unittests/tsserver/documentRegistry.ts @@ -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); diff --git a/src/testRunner/unittests/tsserver/duplicatePackages.ts b/src/testRunner/unittests/tsserver/duplicatePackages.ts index 7dac9af67e0..41b7565b51f 100644 --- a/src/testRunner/unittests/tsserver/duplicatePackages.ts +++ b/src/testRunner/unittests/tsserver/duplicatePackages.ts @@ -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(session, ts.projectSystem.protocol.CommandTypes.GetCodeFixes, { + const response = executeSessionRequest(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(response, [ + assert.deepEqual(response, [ { description: `Add import from "foo"`, fixName: "import", diff --git a/src/testRunner/unittests/tsserver/dynamicFiles.ts b/src/testRunner/unittests/tsserver/dynamicFiles.ts index 8ef9fd038b4..007ba4d02d6 100644 --- a/src/testRunner/unittests/tsserver/dynamicFiles.ts +++ b/src/testRunner/unittests/tsserver/dynamicFiles.ts @@ -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: `/// /// 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(session, ts.projectSystem.protocol.CommandTypes.Open, { + executeSessionRequestNoResponse(session, ts.server.protocol.CommandTypes.Open, { file: untitledFile, fileContent: `/// \nlet foo = 1;\nfooo/**/`, scriptKindName: "TS", projectRootPath: "/proj", }); verifyDynamic(session.getProjectService(), `/proj/untitled:^untitled-1`); - const response = ts.projectSystem.executeSessionRequest(session, ts.projectSystem.protocol.CommandTypes.GetCodeFixes, { + const response = executeSessionRequest(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(response, [ + assert.deepEqual(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({ - command: ts.projectSystem.protocol.CommandTypes.GetOutliningSpans, + session.executeCommandSeq({ + 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]); }); }); diff --git a/src/testRunner/unittests/tsserver/events/largeFileReferenced.ts b/src/testRunner/unittests/tsserver/events/largeFileReferenced.ts index 57a295d8cf8..61c60887ea6 100644 --- a/src/testRunner/unittests/tsserver/events/largeFileReferenced.ts +++ b/src/testRunner/unittests/tsserver/events/largeFileReferenced.ts @@ -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(host, ts.server.LargeFileReferencedEvent); + const host = createServerHost(files); + const { session, events: largeFileReferencedEvents } = createSessionWithEventTracking(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]); }); } diff --git a/src/testRunner/unittests/tsserver/events/projectLanguageServiceState.ts b/src/testRunner/unittests/tsserver/events/projectLanguageServiceState.ts index 7fcb0b56c42..ac95c7d01a5 100644 --- a/src/testRunner/unittests/tsserver/events/projectLanguageServiceState.ts +++ b/src/testRunner/unittests/tsserver/events/projectLanguageServiceState.ts @@ -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(host, ts.server.ProjectLanguageServiceStateEvent); + const { session, events } = createSessionWithEventTracking(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); }); }); diff --git a/src/testRunner/unittests/tsserver/events/projectLoading.ts b/src/testRunner/unittests/tsserver/events/projectLoading.ts index ee8d0241572..34bf3d736fd 100644 --- a/src/testRunner/unittests/tsserver/events/projectLoading.ts +++ b/src/testRunner/unittests/tsserver/events/projectLoading.ts @@ -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({ - command: ts.projectSystem.protocol.CommandTypes.References, + session.executeCommandSeq({ + 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(host, [ts.server.ProjectLoadingStartEvent, ts.server.ProjectLoadingFinishEvent]); + const { session, events } = createSessionWithEventTracking(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(host, [ts.server.ProjectLoadingStartEvent, ts.server.ProjectLoadingFinishEvent]); + const { session, getEvents, clearEvents } = createSessionWithDefaultEventHandler(host, [ts.server.ProjectLoadingStartEvent, ts.server.ProjectLoadingFinishEvent]); return { session, getNumberOfEvents: () => getEvents().length, diff --git a/src/testRunner/unittests/tsserver/events/projectUpdatedInBackground.ts b/src/testRunner/unittests/tsserver/events/projectUpdatedInBackground.ts index 47d51d169c1..41555be968e 100644 --- a/src/testRunner/unittests/tsserver/events/projectUpdatedInBackground.ts +++ b/src/testRunner/unittests/tsserver/events/projectUpdatedInBackground.ts @@ -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({ + function updateContentOfOpenFile(file: File, newContent: string) { + session.executeCommandSeq({ 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: ` /// export var t1 = 10;` }; - const file2: ts.projectSystem.File = { + const file2: File = { path: "/a/b/file2.ts", content: ` /// @@ -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: ` /// @@ -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: ` /// @@ -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( + function createSessionWithProjectChangedEventHandler(host: TestServerHost, logger: Logger | undefined): ProjectsUpdatedInBackgroundEventVerifier { + const { session, events: projectChangedEvents } = createSessionWithEventTracking( 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( + function createSessionThatUsesEvents(host: TestServerHost, logger: Logger | undefined, noGetErrOnBackgroundUpdate?: boolean): ProjectsUpdatedInBackgroundEventVerifier { + const { session, getEvents, clearEvents } = createSessionWithDefaultEventHandler( 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 }; diff --git a/src/testRunner/unittests/tsserver/exportMapCache.ts b/src/testRunner/unittests/tsserver/exportMapCache.ts index 4cbb70fd456..6e195e47724 100644 --- a/src/testRunner/unittests/tsserver/exportMapCache.ts +++ b/src/testRunner/unittests/tsserver/exportMapCache.ts @@ -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({ - command: ts.projectSystem.protocol.CommandTypes.UpdateOpen, + session.executeCommandSeq({ + 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(session, ts.projectSystem.protocol.CommandTypes.CompletionInfo, { + executeSessionRequest(session, ts.server.protocol.CommandTypes.CompletionInfo, { ...requestLocation, includeExternalModuleExports: true, prefix: "foo", diff --git a/src/testRunner/unittests/tsserver/externalProjects.ts b/src/testRunner/unittests/tsserver/externalProjects.ts index cbd3ffced23..b6cd6ecdb96 100644 --- a/src/testRunner/unittests/tsserver/externalProjects.ts +++ b/src/testRunner/unittests/tsserver/externalProjects.ts @@ -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 }); }); }); diff --git a/src/testRunner/unittests/tsserver/forceConsistentCasingInFileNames.ts b/src/testRunner/unittests/tsserver/forceConsistentCasingInFileNames.ts index 74551041f8f..c2dc254e961 100644 --- a/src/testRunner/unittests/tsserver/forceConsistentCasingInFileNames.ts +++ b/src/testRunner/unittests/tsserver/forceConsistentCasingInFileNames.ts @@ -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({ - command: ts.projectSystem.protocol.CommandTypes.UpdateOpen, + openFilesForSession([{ file: anotherFile, projectRootPath: "/user/username/projects/myproject" }], session); + session.executeCommandSeq({ + 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({ - command: ts.projectSystem.protocol.CommandTypes.UpdateOpen, + session.executeCommandSeq({ + 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); }); }); diff --git a/src/testRunner/unittests/tsserver/formatSettings.ts b/src/testRunner/unittests/tsserver/formatSettings.ts index 0fde7703d3e..b6218b77827 100644 --- a/src/testRunner/unittests/tsserver/formatSettings.ts +++ b/src/testRunner/unittests/tsserver/formatSettings.ts @@ -1,4 +1,6 @@ import * as ts from "../../_namespaces/ts"; +import { createServerHost } from "../virtualFileSystemWithWatch"; +import { createProjectService } from "./helpers"; describe("unittests:: tsserver:: format settings", () => { it("can be set globally", () => { @@ -6,8 +8,8 @@ describe("unittests:: tsserver:: format settings", () => { path: "/a/b/app.ts", content: "let x;" }; - const host = ts.projectSystem.createServerHost([f1]); - const projectService = ts.projectSystem.createProjectService(host); + const host = createServerHost([f1]); + const projectService = createProjectService(host); projectService.openClientFile(f1.path); const defaultSettings = projectService.getFormatCodeOptions(f1.path as ts.server.NormalizedPath); diff --git a/src/testRunner/unittests/tsserver/getApplicableRefactors.ts b/src/testRunner/unittests/tsserver/getApplicableRefactors.ts index 65497bb2bc3..43004a13f8c 100644 --- a/src/testRunner/unittests/tsserver/getApplicableRefactors.ts +++ b/src/testRunner/unittests/tsserver/getApplicableRefactors.ts @@ -1,12 +1,14 @@ import * as ts from "../../_namespaces/ts"; +import { createServerHost, File } from "../virtualFileSystemWithWatch"; +import { createSession, openFilesForSession, executeSessionRequest } from "./helpers"; describe("unittests:: tsserver:: getApplicableRefactors", () => { it("works when taking position", () => { - const aTs: ts.projectSystem.File = { path: "/a.ts", content: "" }; - const session = ts.projectSystem.createSession(ts.projectSystem.createServerHost([aTs])); - ts.projectSystem.openFilesForSession([aTs], session); - const response = ts.projectSystem.executeSessionRequest( - session, ts.projectSystem.protocol.CommandTypes.GetApplicableRefactors, { file: aTs.path, line: 1, offset: 1 }); - assert.deepEqual(response, []); + const aTs: File = { path: "/a.ts", content: "" }; + const session = createSession(createServerHost([aTs])); + openFilesForSession([aTs], session); + const response = executeSessionRequest( + session, ts.server.protocol.CommandTypes.GetApplicableRefactors, { file: aTs.path, line: 1, offset: 1 }); + assert.deepEqual(response, []); }); }); diff --git a/src/testRunner/unittests/tsserver/getEditsForFileRename.ts b/src/testRunner/unittests/tsserver/getEditsForFileRename.ts index 89e3d708bee..9b28cc90512 100644 --- a/src/testRunner/unittests/tsserver/getEditsForFileRename.ts +++ b/src/testRunner/unittests/tsserver/getEditsForFileRename.ts @@ -1,22 +1,24 @@ import * as ts from "../../_namespaces/ts"; +import { createServerHost, File } from "../virtualFileSystemWithWatch"; +import { createProjectService, textSpanFromSubstring, createSession, openFilesForSession, executeSessionRequest, protocolTextSpanFromSubstring } from "./helpers"; describe("unittests:: tsserver:: getEditsForFileRename", () => { it("works for host implementing 'resolveModuleNames' and 'getResolvedModuleWithFailedLookupLocationsFromCache'", () => { - const userTs: ts.projectSystem.File = { + const userTs: File = { path: "/user.ts", content: 'import { x } from "./old";', }; - const newTs: ts.projectSystem.File = { + const newTs: File = { path: "/new.ts", content: "export const x = 0;", }; - const tsconfig: ts.projectSystem.File = { + const tsconfig: File = { path: "/tsconfig.json", content: "{}", }; - const host = ts.projectSystem.createServerHost([userTs, newTs, tsconfig]); - const projectService = ts.projectSystem.createProjectService(host); + const host = createServerHost([userTs, newTs, tsconfig]); + const projectService = createProjectService(host); projectService.openClientFile(userTs.path); const project = projectService.configuredProjects.get(tsconfig.path)!; @@ -26,79 +28,79 @@ describe("unittests:: tsserver:: getEditsForFileRename", () => { assert.deepEqual(edits, [{ fileName: "/user.ts", textChanges: [{ - span: ts.projectSystem.textSpanFromSubstring(userTs.content, "./old"), + span: textSpanFromSubstring(userTs.content, "./old"), newText: "./new", }], }]); }); it("works with multiple projects", () => { - const aUserTs: ts.projectSystem.File = { + const aUserTs: File = { path: "/a/user.ts", content: 'import { x } from "./old";', }; - const aOldTs: ts.projectSystem.File = { + const aOldTs: File = { path: "/a/old.ts", content: "export const x = 0;", }; - const aTsconfig: ts.projectSystem.File = { + const aTsconfig: File = { path: "/a/tsconfig.json", content: JSON.stringify({ files: ["./old.ts", "./user.ts"] }), }; - const bUserTs: ts.projectSystem.File = { + const bUserTs: File = { path: "/b/user.ts", content: 'import { x } from "../a/old";', }; - const bTsconfig: ts.projectSystem.File = { + const bTsconfig: File = { path: "/b/tsconfig.json", content: "{}", }; - const host = ts.projectSystem.createServerHost([aUserTs, aOldTs, aTsconfig, bUserTs, bTsconfig]); - const session = ts.projectSystem.createSession(host); - ts.projectSystem.openFilesForSession([aUserTs, bUserTs], session); + const host = createServerHost([aUserTs, aOldTs, aTsconfig, bUserTs, bTsconfig]); + const session = createSession(host); + openFilesForSession([aUserTs, bUserTs], session); - const response = ts.projectSystem.executeSessionRequest(session, ts.projectSystem.CommandNames.GetEditsForFileRename, { + const response = executeSessionRequest(session, ts.server.CommandNames.GetEditsForFileRename, { oldFilePath: aOldTs.path, newFilePath: "/a/new.ts", }); - assert.deepEqual(response, [ + assert.deepEqual(response, [ { fileName: aTsconfig.path, - textChanges: [{ ...ts.projectSystem.protocolTextSpanFromSubstring(aTsconfig.content, "./old.ts"), newText: "new.ts" }], + textChanges: [{ ...protocolTextSpanFromSubstring(aTsconfig.content, "./old.ts"), newText: "new.ts" }], }, { fileName: aUserTs.path, - textChanges: [{ ...ts.projectSystem.protocolTextSpanFromSubstring(aUserTs.content, "./old"), newText: "./new" }], + textChanges: [{ ...protocolTextSpanFromSubstring(aUserTs.content, "./old"), newText: "./new" }], }, { fileName: bUserTs.path, - textChanges: [{ ...ts.projectSystem.protocolTextSpanFromSubstring(bUserTs.content, "../a/old"), newText: "../a/new" }], + textChanges: [{ ...protocolTextSpanFromSubstring(bUserTs.content, "../a/old"), newText: "../a/new" }], }, ]); }); it("works with file moved to inferred project", () => { - const aTs: ts.projectSystem.File = { path: "/a.ts", content: 'import {} from "./b";' }; - const cTs: ts.projectSystem.File = { path: "/c.ts", content: "export {};" }; - const tsconfig: ts.projectSystem.File = { path: "/tsconfig.json", content: JSON.stringify({ files: ["./a.ts", "./b.ts"] }) }; + const aTs: File = { path: "/a.ts", content: 'import {} from "./b";' }; + const cTs: File = { path: "/c.ts", content: "export {};" }; + const tsconfig: File = { path: "/tsconfig.json", content: JSON.stringify({ files: ["./a.ts", "./b.ts"] }) }; - const host = ts.projectSystem.createServerHost([aTs, cTs, tsconfig]); - const session = ts.projectSystem.createSession(host); - ts.projectSystem.openFilesForSession([aTs, cTs], session); + const host = createServerHost([aTs, cTs, tsconfig]); + const session = createSession(host); + openFilesForSession([aTs, cTs], session); - const response = ts.projectSystem.executeSessionRequest(session, ts.projectSystem.CommandNames.GetEditsForFileRename, { + const response = executeSessionRequest(session, ts.server.CommandNames.GetEditsForFileRename, { oldFilePath: "/b.ts", newFilePath: cTs.path, }); - assert.deepEqual(response, [ + assert.deepEqual(response, [ { fileName: "/tsconfig.json", - textChanges: [{ ...ts.projectSystem.protocolTextSpanFromSubstring(tsconfig.content, "./b.ts"), newText: "c.ts" }], + textChanges: [{ ...protocolTextSpanFromSubstring(tsconfig.content, "./b.ts"), newText: "c.ts" }], }, { fileName: "/a.ts", - textChanges: [{ ...ts.projectSystem.protocolTextSpanFromSubstring(aTs.content, "./b"), newText: "./c" }], + textChanges: [{ ...protocolTextSpanFromSubstring(aTs.content, "./b"), newText: "./c" }], }, ]); }); diff --git a/src/testRunner/unittests/tsserver/getExportReferences.ts b/src/testRunner/unittests/tsserver/getExportReferences.ts index f1009a8d56f..7b815263158 100644 --- a/src/testRunner/unittests/tsserver/getExportReferences.ts +++ b/src/testRunner/unittests/tsserver/getExportReferences.ts @@ -1,4 +1,6 @@ import * as ts from "../../_namespaces/ts"; +import { createServerHost, File } from "../virtualFileSystemWithWatch"; +import { createSession, openFilesForSession, makeReferenceItem, MakeReferenceItem, executeSessionRequest, protocolFileLocationFromSubstring, protocolLocationFromSubstring } from "./helpers"; describe("unittests:: tsserver:: getExportReferences", () => { const exportVariable = "export const value = 0;"; @@ -6,11 +8,11 @@ describe("unittests:: tsserver:: getExportReferences", () => { const exportObjectDestructured = "export const { valueC, valueD: renamedD } = { valueC: 0, valueD: 1 };"; const exportNestedObject = "export const { nest: [valueE, { valueF }] } = { nest: [0, { valueF: 1 }] };"; - const mainTs: ts.projectSystem.File = { + const mainTs: File = { path: "/main.ts", content: 'import { value, valueA, valueB, valueC, renamedD, valueE, valueF } from "./mod";', }; - const modTs: ts.projectSystem.File = { + const modTs: File = { path: "/mod.ts", content: `${exportVariable} ${exportArrayDestructured} @@ -18,20 +20,20 @@ ${exportObjectDestructured} ${exportNestedObject} `, }; - const tsconfig: ts.projectSystem.File = { + const tsconfig: File = { path: "/tsconfig.json", content: "{}", }; function makeSampleSession() { - const host = ts.projectSystem.createServerHost([mainTs, modTs, tsconfig]); - const session = ts.projectSystem.createSession(host); - ts.projectSystem.openFilesForSession([mainTs, modTs], session); + const host = createServerHost([mainTs, modTs, tsconfig]); + const session = createSession(host); + openFilesForSession([mainTs, modTs], session); return session; } - const referenceMainTs = (mainTs: ts.projectSystem.File, text: string): ts.projectSystem.protocol.ReferencesResponseItem => - ts.projectSystem.makeReferenceItem({ + const referenceMainTs = (mainTs: File, text: string): ts.server.protocol.ReferencesResponseItem => + makeReferenceItem({ file: mainTs, isDefinition: false, isWriteAccess: true, @@ -42,9 +44,9 @@ ${exportNestedObject} const referenceModTs = ( texts: { text: string; lineText: string; contextText?: string }, - override: Partial = {}, - ): ts.projectSystem.protocol.ReferencesResponseItem => - ts.projectSystem.makeReferenceItem({ + override: Partial = {}, + ): ts.server.protocol.ReferencesResponseItem => + makeReferenceItem({ file: modTs, isDefinition: true, ...texts, @@ -54,10 +56,10 @@ ${exportNestedObject} it("should get const variable declaration references", () => { const session = makeSampleSession(); - const response = ts.projectSystem.executeSessionRequest( + const response = executeSessionRequest( session, - ts.projectSystem.protocol.CommandTypes.References, - ts.projectSystem.protocolFileLocationFromSubstring(modTs, "value"), + ts.server.protocol.CommandTypes.References, + protocolFileLocationFromSubstring(modTs, "value"), ); const expectResponse = { @@ -67,7 +69,7 @@ ${exportNestedObject} ], symbolDisplayString: "const value: 0", symbolName: "value", - symbolStartOffset: ts.projectSystem.protocolLocationFromSubstring(modTs.content, "value").offset, + symbolStartOffset: protocolLocationFromSubstring(modTs.content, "value").offset, }; assert.deepEqual(response, expectResponse); @@ -75,10 +77,10 @@ ${exportNestedObject} it("should get array destructuring declaration references", () => { const session = makeSampleSession(); - const response = ts.projectSystem.executeSessionRequest( + const response = executeSessionRequest( session, - ts.projectSystem.protocol.CommandTypes.References, - ts.projectSystem.protocolFileLocationFromSubstring(modTs, "valueA"), + ts.server.protocol.CommandTypes.References, + protocolFileLocationFromSubstring(modTs, "valueA"), ); const expectResponse = { @@ -92,7 +94,7 @@ ${exportNestedObject} ], symbolDisplayString: "const valueA: number", symbolName: "valueA", - symbolStartOffset: ts.projectSystem.protocolLocationFromSubstring(modTs.content, "valueA").offset, + symbolStartOffset: protocolLocationFromSubstring(modTs.content, "valueA").offset, }; assert.deepEqual(response, expectResponse); @@ -100,10 +102,10 @@ ${exportNestedObject} it("should get object destructuring declaration references", () => { const session = makeSampleSession(); - const response = ts.projectSystem.executeSessionRequest( + const response = executeSessionRequest( session, - ts.projectSystem.protocol.CommandTypes.References, - ts.projectSystem.protocolFileLocationFromSubstring(modTs, "valueC"), + ts.server.protocol.CommandTypes.References, + protocolFileLocationFromSubstring(modTs, "valueC"), ); const expectResponse = { refs: [ @@ -123,7 +125,7 @@ ${exportNestedObject} ], symbolDisplayString: "const valueC: number", symbolName: "valueC", - symbolStartOffset: ts.projectSystem.protocolLocationFromSubstring(modTs.content, "valueC").offset, + symbolStartOffset: protocolLocationFromSubstring(modTs.content, "valueC").offset, }; assert.deepEqual(response, expectResponse); @@ -131,10 +133,10 @@ ${exportNestedObject} it("should get object declaration references that renames destructured property", () => { const session = makeSampleSession(); - const response = ts.projectSystem.executeSessionRequest( + const response = executeSessionRequest( session, - ts.projectSystem.protocol.CommandTypes.References, - ts.projectSystem.protocolFileLocationFromSubstring(modTs, "renamedD"), + ts.server.protocol.CommandTypes.References, + protocolFileLocationFromSubstring(modTs, "renamedD"), ); const expectResponse = { @@ -148,7 +150,7 @@ ${exportNestedObject} ], symbolDisplayString: "const renamedD: number", symbolName: "renamedD", - symbolStartOffset: ts.projectSystem.protocolLocationFromSubstring(modTs.content, "renamedD").offset, + symbolStartOffset: protocolLocationFromSubstring(modTs.content, "renamedD").offset, }; assert.deepEqual(response, expectResponse); @@ -156,10 +158,10 @@ ${exportNestedObject} it("should get nested object declaration references", () => { const session = makeSampleSession(); - const response = ts.projectSystem.executeSessionRequest( + const response = executeSessionRequest( session, - ts.projectSystem.protocol.CommandTypes.References, - ts.projectSystem.protocolFileLocationFromSubstring(modTs, "valueF"), + ts.server.protocol.CommandTypes.References, + protocolFileLocationFromSubstring(modTs, "valueF"), ); const expectResponse = { @@ -185,7 +187,7 @@ ${exportNestedObject} ], symbolDisplayString: "const valueF: number", symbolName: "valueF", - symbolStartOffset: ts.projectSystem.protocolLocationFromSubstring(modTs.content, "valueF").offset, + symbolStartOffset: protocolLocationFromSubstring(modTs.content, "valueF").offset, }; assert.deepEqual(response, expectResponse); diff --git a/src/testRunner/unittests/tsserver/getFileReferences.ts b/src/testRunner/unittests/tsserver/getFileReferences.ts index 1db68ae8ea9..37e0381d04c 100644 --- a/src/testRunner/unittests/tsserver/getFileReferences.ts +++ b/src/testRunner/unittests/tsserver/getFileReferences.ts @@ -1,4 +1,6 @@ import * as ts from "../../_namespaces/ts"; +import { createServerHost, File } from "../virtualFileSystemWithWatch"; +import { createSession, openFilesForSession, executeSessionRequest, makeReferenceItem } from "./helpers"; describe("unittests:: tsserver:: getFileReferences", () => { const importA = `import "./a";`; @@ -6,49 +8,49 @@ describe("unittests:: tsserver:: getFileReferences", () => { const importAFromA = `import { a } from "/project/a";`; const typeofImportA = `type T = typeof import("./a").a;`; - const aTs: ts.projectSystem.File = { + const aTs: File = { path: "/project/a.ts", content: "export const a = {};", }; - const bTs: ts.projectSystem.File = { + const bTs: File = { path: "/project/b.ts", content: importA, }; - const cTs: ts.projectSystem.File = { + const cTs: File = { path: "/project/c.ts", content: importCurlyFromA }; - const dTs: ts.projectSystem.File = { + const dTs: File = { path: "/project/d.ts", content: [importAFromA, typeofImportA].join("\n") }; - const tsconfig: ts.projectSystem.File = { + const tsconfig: File = { path: "/project/tsconfig.json", content: "{}", }; function makeSampleSession() { - const host = ts.projectSystem.createServerHost([aTs, bTs, cTs, dTs, tsconfig]); - const session = ts.projectSystem.createSession(host); - ts.projectSystem.openFilesForSession([aTs, bTs, cTs, dTs], session); + const host = createServerHost([aTs, bTs, cTs, dTs, tsconfig]); + const session = createSession(host); + openFilesForSession([aTs, bTs, cTs, dTs], session); return session; } it("should get file references", () => { const session = makeSampleSession(); - const response = ts.projectSystem.executeSessionRequest( + const response = executeSessionRequest( session, - ts.projectSystem.protocol.CommandTypes.FileReferences, + ts.server.protocol.CommandTypes.FileReferences, { file: aTs.path }, ); - const expectResponse: ts.projectSystem.protocol.FileReferencesResponseBody = { + const expectResponse: ts.server.protocol.FileReferencesResponseBody = { refs: [ - ts.projectSystem.makeReferenceItem({ file: bTs, text: "./a", lineText: importA, contextText: importA, isWriteAccess: false }), - ts.projectSystem.makeReferenceItem({ file: cTs, text: "./a", lineText: importCurlyFromA, contextText: importCurlyFromA, isWriteAccess: false }), - ts.projectSystem.makeReferenceItem({ file: dTs, text: "/project/a", lineText: importAFromA, contextText: importAFromA, isWriteAccess: false }), - ts.projectSystem.makeReferenceItem({ file: dTs, text: "./a", lineText: typeofImportA, contextText: typeofImportA, isWriteAccess: false }), + makeReferenceItem({ file: bTs, text: "./a", lineText: importA, contextText: importA, isWriteAccess: false }), + makeReferenceItem({ file: cTs, text: "./a", lineText: importCurlyFromA, contextText: importCurlyFromA, isWriteAccess: false }), + makeReferenceItem({ file: dTs, text: "/project/a", lineText: importAFromA, contextText: importAFromA, isWriteAccess: false }), + makeReferenceItem({ file: dTs, text: "./a", lineText: typeofImportA, contextText: typeofImportA, isWriteAccess: false }), ], symbolName: `"${aTs.path}"`, }; @@ -60,18 +62,18 @@ describe("unittests:: tsserver:: getFileReferences", () => { const session = makeSampleSession(); session.getProjectService().setHostConfiguration({ preferences: { disableLineTextInReferences: true } }); - const response = ts.projectSystem.executeSessionRequest( + const response = executeSessionRequest( session, - ts.projectSystem.protocol.CommandTypes.FileReferences, + ts.server.protocol.CommandTypes.FileReferences, { file: aTs.path }, ); - const expectResponse: ts.projectSystem.protocol.FileReferencesResponseBody = { + const expectResponse: ts.server.protocol.FileReferencesResponseBody = { refs: [ - ts.projectSystem.makeReferenceItem({ file: bTs, text: "./a", lineText: undefined, contextText: importA, isWriteAccess: false }), - ts.projectSystem.makeReferenceItem({ file: cTs, text: "./a", lineText: undefined, contextText: importCurlyFromA, isWriteAccess: false }), - ts.projectSystem.makeReferenceItem({ file: dTs, text: "/project/a", lineText: undefined, contextText: importAFromA, isWriteAccess: false }), - ts.projectSystem.makeReferenceItem({ file: dTs, text: "./a", lineText: undefined, contextText: typeofImportA, isWriteAccess: false }), + makeReferenceItem({ file: bTs, text: "./a", lineText: undefined, contextText: importA, isWriteAccess: false }), + makeReferenceItem({ file: cTs, text: "./a", lineText: undefined, contextText: importCurlyFromA, isWriteAccess: false }), + makeReferenceItem({ file: dTs, text: "/project/a", lineText: undefined, contextText: importAFromA, isWriteAccess: false }), + makeReferenceItem({ file: dTs, text: "./a", lineText: undefined, contextText: typeofImportA, isWriteAccess: false }), ], symbolName: `"${aTs.path}"`, }; diff --git a/src/testRunner/unittests/tsserver/helpers.ts b/src/testRunner/unittests/tsserver/helpers.ts index 4c56d91fd86..c5761dd4b91 100644 --- a/src/testRunner/unittests/tsserver/helpers.ts +++ b/src/testRunner/unittests/tsserver/helpers.ts @@ -1,21 +1,8 @@ import * as ts from "../../_namespaces/ts"; import * as Harness from "../../_namespaces/Harness"; import * as Utils from "../../_namespaces/Utils"; - -export import TI = ts.server.typingsInstaller; -export import protocol = ts.server.protocol; -export import CommandNames = ts.server.CommandNames; - -export import TestServerHost = ts.TestFSWithWatch.TestServerHost; -export type File = ts.TestFSWithWatch.File; -export type SymLink = ts.TestFSWithWatch.SymLink; -export type Folder = ts.TestFSWithWatch.Folder; -export import createServerHost = ts.TestFSWithWatch.createServerHost; -export import checkArray = ts.TestFSWithWatch.checkArray; -export import libFile = ts.TestFSWithWatch.libFile; - -export import commonFile1 = ts.tscWatch.commonFile1; -export import commonFile2 = ts.tscWatch.commonFile2; +import { changeToHostTrackingWrittenFiles, checkArray, createServerHost, File, FileOrFolderOrSymLink, libFile, TestServerHost, TestServerHostTrackingWrittenFiles } from "../virtualFileSystemWithWatch"; +import { ensureErrorFreeBuild } from "../tscWatch/helpers"; const outputEventRegex = /Content\-Length: [\d]+\r\n\r\n/; export function mapOutputToJson(s: string) { @@ -51,7 +38,7 @@ export const customTypesMap = { export interface PostExecAction { readonly success: boolean; - readonly callback: TI.RequestCompletedAction; + readonly callback: ts.server.typingsInstaller.RequestCompletedAction; } export interface Logger extends ts.server.Logger { @@ -174,14 +161,14 @@ export function appendProjectFileText(project: ts.server.Project, logs: string[] logs.push(""); } -export class TestTypingsInstaller extends TI.TypingsInstaller implements ts.server.ITypingsInstaller { +export class TestTypingsInstaller extends ts.server.typingsInstaller.TypingsInstaller implements ts.server.ITypingsInstaller { protected projectService!: ts.server.ProjectService; constructor( readonly globalTypingsCacheLocation: string, throttleLimit: number, installTypingHost: ts.server.ServerHost, readonly typesRegistry = new ts.Map>(), - log?: TI.Log) { + log?: ts.server.typingsInstaller.Log) { super(installTypingHost, globalTypingsCacheLocation, "/safeList.json" as ts.Path, customTypesMap.path, throttleLimit, log); } @@ -213,7 +200,7 @@ export class TestTypingsInstaller extends TI.TypingsInstaller implements ts.serv return this.installTypingHost; } - installWorker(_requestId: number, _args: string[], _cwd: string, cb: TI.RequestCompletedAction): void { + installWorker(_requestId: number, _args: string[], _cwd: string, cb: ts.server.typingsInstaller.RequestCompletedAction): void { this.addPostExecAction("success", cb); } @@ -226,7 +213,7 @@ export class TestTypingsInstaller extends TI.TypingsInstaller implements ts.serv this.install(request); } - addPostExecAction(stdout: string | string[], cb: TI.RequestCompletedAction) { + addPostExecAction(stdout: string | string[], cb: ts.server.typingsInstaller.RequestCompletedAction) { const out = ts.isString(stdout) ? stdout : createNpmPackageJsonString(stdout); const action: PostExecAction = { success: !!out, @@ -263,7 +250,7 @@ export function createTypesRegistry(...list: string[]): ts.ESMap(type: "request" | "response", requestOrResult: T): T { + private baseline(type: "request" | "response", requestOrResult: T): T { if (!this.logger.hasLevel(ts.server.LogLevel.verbose)) return requestOrResult; if (type === "request") this.logger.info(`request:${ts.server.indent(JSON.stringify(requestOrResult, undefined, 2))}`); this.testhost.baselineHost(type === "request" ? "Before request" : "After request"); @@ -499,7 +486,7 @@ export function createSessionWithEventTracking(host: TestServerHost, eventNames: T["event"] | T["event"][], opts: Partial = {}) { +export function createSessionWithDefaultEventHandler(host: TestServerHost, eventNames: T["event"] | T["event"][], opts: Partial = {}) { const session = createSession(host, { canUseEvents: true, ...opts }); return { @@ -540,7 +527,7 @@ export class TestProjectService extends ts.server.ProjectService { ...opts }); this.testhost = patchHostTimeouts( - ts.TestFSWithWatch.changeToHostTrackingWrittenFiles(this.host as TestServerHost), + changeToHostTrackingWrittenFiles(this.host as TestServerHost), this ); this.testhost.baselineHost("Creating project service"); @@ -628,13 +615,13 @@ export function getConfigFilesToWatch(folder: string) { ]; } -export function protocolLocationFromSubstring(str: string, substring: string, options?: SpanFromSubstringOptions): protocol.Location { +export function protocolLocationFromSubstring(str: string, substring: string, options?: SpanFromSubstringOptions): ts.server.protocol.Location { const start = nthIndexOf(str, substring, options ? options.index : 0); ts.Debug.assert(start !== -1); return protocolToLocation(str)(start); } -export function protocolToLocation(text: string): (pos: number) => protocol.Location { +export function protocolToLocation(text: string): (pos: number) => ts.server.protocol.Location { const lineStarts = ts.computeLineStarts(text); return pos => { const x = ts.computeLineAndCharacterOfPosition(lineStarts, pos); @@ -642,7 +629,7 @@ export function protocolToLocation(text: string): (pos: number) => protocol.Loca }; } -export function protocolTextSpanFromSubstring(str: string, substring: string, options?: SpanFromSubstringOptions): protocol.TextSpan { +export function protocolTextSpanFromSubstring(str: string, substring: string, options?: SpanFromSubstringOptions): ts.server.protocol.TextSpan { const span = textSpanFromSubstring(str, substring, options); const toLocation = protocolToLocation(str); return { start: toLocation(span.start), end: toLocation(ts.textSpanEnd(span)) }; @@ -655,7 +642,7 @@ export interface DocumentSpanFromSubstring { contextText?: string; contextOptions?: SpanFromSubstringOptions; } -export function protocolFileSpanFromSubstring({ file, text, options }: DocumentSpanFromSubstring): protocol.FileSpan { +export function protocolFileSpanFromSubstring({ file, text, options }: DocumentSpanFromSubstring): ts.server.protocol.FileSpan { return { file: file.path, ...protocolTextSpanFromSubstring(file.content, text, options) }; } @@ -666,7 +653,7 @@ interface FileSpanWithContextFromSubString { contextText?: string; contextOptions?: SpanFromSubstringOptions; } -export function protocolFileSpanWithContextFromSubstring({ contextText, contextOptions, ...rest }: FileSpanWithContextFromSubString): protocol.FileSpanWithContext { +export function protocolFileSpanWithContextFromSubstring({ contextText, contextOptions, ...rest }: FileSpanWithContextFromSubString): ts.server.protocol.FileSpanWithContext { const result = protocolFileSpanFromSubstring(rest); const contextSpan = contextText !== undefined ? protocolFileSpanFromSubstring({ file: rest.file, text: contextText, options: contextOptions }) : @@ -687,7 +674,7 @@ export interface ProtocolTextSpanWithContextFromString { contextText?: string; contextOptions?: SpanFromSubstringOptions; } -export function protocolTextSpanWithContextFromSubstring({ fileText, text, options, contextText, contextOptions }: ProtocolTextSpanWithContextFromString): protocol.TextSpanWithContext { +export function protocolTextSpanWithContextFromSubstring({ fileText, text, options, contextText, contextOptions }: ProtocolTextSpanWithContextFromString): ts.server.protocol.TextSpanWithContext { const span = textSpanFromSubstring(fileText, text, options); const toLocation = protocolToLocation(fileText); const contextSpan = contextText !== undefined ? textSpanFromSubstring(fileText, contextText, contextOptions) : undefined; @@ -707,7 +694,7 @@ export interface ProtocolRenameSpanFromSubstring extends ProtocolTextSpanWithCon readonly suffixText?: string; }; } -export function protocolRenameSpanFromSubstring({ prefixSuffixText, ...rest }: ProtocolRenameSpanFromSubstring): protocol.RenameTextSpan { +export function protocolRenameSpanFromSubstring({ prefixSuffixText, ...rest }: ProtocolRenameSpanFromSubstring): ts.server.protocol.RenameTextSpan { return { ...protocolTextSpanWithContextFromSubstring(rest), ...prefixSuffixText @@ -720,7 +707,7 @@ export function textSpanFromSubstring(str: string, substring: string, options?: return ts.createTextSpan(start, substring.length); } -export function protocolFileLocationFromSubstring(file: File, substring: string, options?: SpanFromSubstringOptions): protocol.FileLocationRequestArgs { +export function protocolFileLocationFromSubstring(file: File, substring: string, options?: SpanFromSubstringOptions): ts.server.protocol.FileLocationRequestArgs { return { file: file.path, ...protocolLocationFromSubstring(file.content, substring, options) }; } @@ -780,7 +767,7 @@ export class TestServerCancellationToken implements ts.server.ServerCancellation } } -export function makeSessionRequest(command: string, args: T): protocol.Request { +export function makeSessionRequest(command: string, args: T): ts.server.protocol.Request { return { seq: 0, type: "request", @@ -789,24 +776,24 @@ export function makeSessionRequest(command: string, args: T): protocol.Reques }; } -export function executeSessionRequest(session: ts.server.Session, command: TRequest["command"], args: TRequest["arguments"]): TResponse["body"] { +export function executeSessionRequest(session: ts.server.Session, command: TRequest["command"], args: TRequest["arguments"]): TResponse["body"] { return session.executeCommand(makeSessionRequest(command, args)).response as TResponse["body"]; } -export function executeSessionRequestNoResponse(session: ts.server.Session, command: TRequest["command"], args: TRequest["arguments"]): void { +export function executeSessionRequestNoResponse(session: ts.server.Session, command: TRequest["command"], args: TRequest["arguments"]): void { session.executeCommand(makeSessionRequest(command, args)); } export function openFilesForSession(files: readonly (File | { readonly file: File | string, readonly projectRootPath: string, content?: string })[], session: ts.server.Session): void { for (const file of files) { - session.executeCommand(makeSessionRequest(CommandNames.Open, + session.executeCommand(makeSessionRequest(ts.server.CommandNames.Open, "projectRootPath" in file ? { file: typeof file.file === "string" ? file.file : file.file.path, projectRootPath: file.projectRootPath } : { file: file.path })); // eslint-disable-line local/no-in-operator } } export function closeFilesForSession(files: readonly File[], session: ts.server.Session): void { for (const file of files) { - session.executeCommand(makeSessionRequest(CommandNames.Close, { file: file.path })); + session.executeCommand(makeSessionRequest(ts.server.CommandNames.Close, { file: file.path })); } } @@ -816,7 +803,7 @@ export interface MakeReferenceItem extends DocumentSpanFromSubstring { lineText?: string; } -export function makeReferenceItem({ isDefinition, isWriteAccess, lineText, ...rest }: MakeReferenceItem): protocol.ReferencesResponseItem { +export function makeReferenceItem({ isDefinition, isWriteAccess, lineText, ...rest }: MakeReferenceItem): ts.server.protocol.ReferencesResponseItem { return { ...protocolFileSpanWithContextFromSubstring(rest), isDefinition, @@ -836,8 +823,8 @@ export interface VerifyGetErrRequest extends VerifyGetErrRequestBase { } export function verifyGetErrRequest(request: VerifyGetErrRequest) { const { session, files } = request; - session.executeCommandSeq({ - command: protocol.CommandTypes.Geterr, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Geterr, arguments: { delay: 0, files: files.map(filePath) } }); checkAllErrors(request); @@ -885,8 +872,8 @@ function verifyErrorsUsingGeterrForProject({ scenario, subScenario, allFiles, op openFilesForSession(openFiles(), session); for (const expected of getErrForProjectRequest()) { - session.executeCommandSeq({ - command: protocol.CommandTypes.GeterrForProject, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.GeterrForProject, arguments: { delay: 0, file: filePath(expected.project) } }); checkAllErrors({ session, host, files: expected.files }); @@ -902,16 +889,16 @@ function verifyErrorsUsingSyncMethods({ scenario, subScenario, allFiles, openFil openFilesForSession(openFiles(), session); for (const { file, project } of syncDiagnostics()) { const reqArgs = { file: filePath(file), projectFileName: project && filePath(project) }; - session.executeCommandSeq({ - command: protocol.CommandTypes.SyntacticDiagnosticsSync, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.SyntacticDiagnosticsSync, arguments: reqArgs }); - session.executeCommandSeq({ - command: protocol.CommandTypes.SemanticDiagnosticsSync, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.SemanticDiagnosticsSync, arguments: reqArgs }); - session.executeCommandSeq({ - command: protocol.CommandTypes.SuggestionDiagnosticsSync, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.SuggestionDiagnosticsSync, arguments: reqArgs }); } @@ -948,9 +935,9 @@ export function verifyDynamic(service: ts.server.ProjectService, path: string) { assert.isTrue(info.isDynamic); } -export function createHostWithSolutionBuild(files: readonly ts.TestFSWithWatch.FileOrFolderOrSymLink[], rootNames: readonly string[]) { - const host = ts.projectSystem.createServerHost(files); +export function createHostWithSolutionBuild(files: readonly FileOrFolderOrSymLink[], rootNames: readonly string[]) { + const host = createServerHost(files); // ts build should succeed - ts.tscWatch.ensureErrorFreeBuild(host, rootNames); + ensureErrorFreeBuild(host, rootNames); return host; } diff --git a/src/testRunner/unittests/tsserver/importHelpers.ts b/src/testRunner/unittests/tsserver/importHelpers.ts index 483ce6edda8..f9f51ecf5dc 100644 --- a/src/testRunner/unittests/tsserver/importHelpers.ts +++ b/src/testRunner/unittests/tsserver/importHelpers.ts @@ -1,4 +1,5 @@ -import * as ts from "../../_namespaces/ts"; +import { createServerHost } from "../virtualFileSystemWithWatch"; +import { createProjectService, toExternalFile } from "./helpers"; describe("unittests:: tsserver:: import helpers", () => { it("should not crash in tsserver", () => { @@ -10,9 +11,9 @@ describe("unittests:: tsserver:: import helpers", () => { path: "/a/node_modules/tslib/index.d.ts", content: "" }; - const host = ts.projectSystem.createServerHost([f1, tslib]); - const service = ts.projectSystem.createProjectService(host); - service.openExternalProject({ projectFileName: "p", rootFiles: [ts.projectSystem.toExternalFile(f1.path)], options: { importHelpers: true } }); + const host = createServerHost([f1, tslib]); + const service = createProjectService(host); + service.openExternalProject({ projectFileName: "p", rootFiles: [toExternalFile(f1.path)], options: { importHelpers: true } }); service.checkNumberOfProjects({ externalProjects: 1 }); }); }); diff --git a/src/testRunner/unittests/tsserver/inferredProjects.ts b/src/testRunner/unittests/tsserver/inferredProjects.ts index 12e51e98107..da8a47e4fde 100644 --- a/src/testRunner/unittests/tsserver/inferredProjects.ts +++ b/src/testRunner/unittests/tsserver/inferredProjects.ts @@ -1,32 +1,35 @@ import * as ts from "../../_namespaces/ts"; +import { createServerHost, File, libFile } from "../virtualFileSystemWithWatch"; +import { commonFile1 } from "../tscWatch/helpers"; +import { createProjectService, createLoggerWithInMemoryLogs, baselineTsserverLogs, checkNumberOfConfiguredProjects, checkNumberOfInferredProjects, checkProjectActualFiles, checkNumberOfProjects, createSession } from "./helpers"; describe("unittests:: tsserver:: Inferred projects", () => { it("create inferred project", () => { - const appFile: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/app.ts`, + const appFile: File = { + path: `/user/username/projects/myproject/app.ts`, content: ` import {f} from "./module" console.log(f) ` }; - const moduleFile: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/module.d.ts`, + const moduleFile: File = { + path: `/user/username/projects/myproject/module.d.ts`, content: `export let x: number` }; - const host = ts.projectSystem.createServerHost([appFile, moduleFile, ts.projectSystem.libFile]); - const projectService = ts.projectSystem.createProjectService(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); + const host = createServerHost([appFile, moduleFile, libFile]); + const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); projectService.openClientFile(appFile.path); - ts.projectSystem.baselineTsserverLogs("inferredProjects", "create inferred project", projectService); + baselineTsserverLogs("inferredProjects", "create inferred project", projectService); }); it("should use only one inferred project if 'useOneInferredProject' is set", () => { const file1 = { - path: `${ts.tscWatch.projectRoot}/a/b/main.ts`, + path: `/user/username/projects/myproject/a/b/main.ts`, content: "let x =1;" }; - const configFile: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/a/b/tsconfig.json`, + const configFile: File = { + path: `/user/username/projects/myproject/a/b/tsconfig.json`, content: `{ "compilerOptions": { "target": "es6" @@ -35,31 +38,31 @@ describe("unittests:: tsserver:: Inferred projects", () => { }` }; const file2 = { - path: `${ts.tscWatch.projectRoot}/a/c/main.ts`, + path: `/user/username/projects/myproject/a/c/main.ts`, content: "let x =1;" }; const file3 = { - path: `${ts.tscWatch.projectRoot}/a/d/main.ts`, + path: `/user/username/projects/myproject/a/d/main.ts`, content: "let x =1;" }; - const host = ts.projectSystem.createServerHost([file1, file2, file3, ts.projectSystem.libFile]); - const projectService = ts.projectSystem.createProjectService(host, { useSingleInferredProject: true }); + const host = createServerHost([file1, file2, file3, libFile]); + const projectService = createProjectService(host, { useSingleInferredProject: true }); projectService.openClientFile(file1.path); projectService.openClientFile(file2.path); projectService.openClientFile(file3.path); - ts.projectSystem.checkNumberOfConfiguredProjects(projectService, 0); - ts.projectSystem.checkNumberOfInferredProjects(projectService, 1); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[0], [file1.path, file2.path, file3.path, ts.projectSystem.libFile.path]); + checkNumberOfConfiguredProjects(projectService, 0); + checkNumberOfInferredProjects(projectService, 1); + checkProjectActualFiles(projectService.inferredProjects[0], [file1.path, file2.path, file3.path, libFile.path]); host.writeFile(configFile.path, configFile.content); host.checkTimeoutQueueLengthAndRun(2); // load configured project from disk + ensureProjectsForOpenFiles - ts.projectSystem.checkNumberOfConfiguredProjects(projectService, 1); - ts.projectSystem.checkNumberOfInferredProjects(projectService, 1); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[0], [file2.path, file3.path, ts.projectSystem.libFile.path]); + checkNumberOfConfiguredProjects(projectService, 1); + checkNumberOfInferredProjects(projectService, 1); + checkProjectActualFiles(projectService.inferredProjects[0], [file2.path, file3.path, libFile.path]); }); it("disable inferred project", () => { @@ -68,12 +71,12 @@ describe("unittests:: tsserver:: Inferred projects", () => { content: "let x =1;" }; - const host = ts.projectSystem.createServerHost([file1]); - const projectService = ts.projectSystem.createProjectService(host, { useSingleInferredProject: true, syntaxOnly: true }); + const host = createServerHost([file1]); + const projectService = createProjectService(host, { useSingleInferredProject: true, syntaxOnly: true }); projectService.openClientFile(file1.path, file1.content); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 1 }); + checkNumberOfProjects(projectService, { inferredProjects: 1 }); const proj = projectService.inferredProjects[0]; assert.isDefined(proj); @@ -89,23 +92,23 @@ describe("unittests:: tsserver:: Inferred projects", () => { path: "/a/mod.ts", content: "export let x: number" }; - const host = ts.projectSystem.createServerHost([file1, modFile]); - const projectService = ts.projectSystem.createProjectService(host); + const host = createServerHost([file1, modFile]); + const projectService = createProjectService(host); projectService.openClientFile(file1.path); projectService.openClientFile(modFile.path); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 2 }); + checkNumberOfProjects(projectService, { inferredProjects: 2 }); const inferredProjects = projectService.inferredProjects.slice(); - ts.projectSystem.checkProjectActualFiles(inferredProjects[0], [file1.path]); - ts.projectSystem.checkProjectActualFiles(inferredProjects[1], [modFile.path]); + checkProjectActualFiles(inferredProjects[0], [file1.path]); + checkProjectActualFiles(inferredProjects[1], [modFile.path]); projectService.setCompilerOptionsForInferredProjects({ moduleResolution: ts.ModuleResolutionKind.Classic }); host.checkTimeoutQueueLengthAndRun(3); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 2 }); + checkNumberOfProjects(projectService, { inferredProjects: 2 }); assert.strictEqual(projectService.inferredProjects[0], inferredProjects[0]); assert.strictEqual(projectService.inferredProjects[1], inferredProjects[1]); - ts.projectSystem.checkProjectActualFiles(inferredProjects[0], [file1.path, modFile.path]); + checkProjectActualFiles(inferredProjects[0], [file1.path, modFile.path]); assert.isTrue(inferredProjects[1].isOrphan()); }); @@ -114,8 +117,8 @@ describe("unittests:: tsserver:: Inferred projects", () => { path: "/a/compile", content: "let x = 1" }; - const host = ts.projectSystem.createServerHost([f]); - const session = ts.projectSystem.createSession(host); + const host = createServerHost([f]); + const session = createSession(host); session.executeCommand({ seq: 1, type: "request", @@ -137,8 +140,8 @@ describe("unittests:: tsserver:: Inferred projects", () => { } } as ts.server.protocol.OpenRequest); const projectService = session.getProjectService(); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 1 }); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[0], [f.path]); + checkNumberOfProjects(projectService, { inferredProjects: 1 }); + checkProjectActualFiles(projectService.inferredProjects[0], [f.path]); }); it("inferred projects per project root", () => { @@ -146,15 +149,15 @@ describe("unittests:: tsserver:: Inferred projects", () => { const file2 = { path: "/a/file2.ts", content: "let y = 2;", projectRootPath: "/a" }; const file3 = { path: "/b/file2.ts", content: "let x = 3;", projectRootPath: "/b" }; const file4 = { path: "/c/file3.ts", content: "let z = 4;" }; - const host = ts.projectSystem.createServerHost([file1, file2, file3, file4]); - const session = ts.projectSystem.createSession(host, { + const host = createServerHost([file1, file2, file3, file4]); + const session = createSession(host, { useSingleInferredProject: true, useInferredProjectPerProjectRoot: true }); session.executeCommand({ seq: 1, type: "request", - command: ts.projectSystem.CommandNames.CompilerOptionsForInferredProjects, + command: ts.server.CommandNames.CompilerOptionsForInferredProjects, arguments: { options: { allowJs: true, @@ -165,7 +168,7 @@ describe("unittests:: tsserver:: Inferred projects", () => { session.executeCommand({ seq: 2, type: "request", - command: ts.projectSystem.CommandNames.CompilerOptionsForInferredProjects, + command: ts.server.CommandNames.CompilerOptionsForInferredProjects, arguments: { options: { allowJs: true, @@ -177,7 +180,7 @@ describe("unittests:: tsserver:: Inferred projects", () => { session.executeCommand({ seq: 3, type: "request", - command: ts.projectSystem.CommandNames.Open, + command: ts.server.CommandNames.Open, arguments: { file: file1.path, fileContent: file1.content, @@ -188,7 +191,7 @@ describe("unittests:: tsserver:: Inferred projects", () => { session.executeCommand({ seq: 4, type: "request", - command: ts.projectSystem.CommandNames.Open, + command: ts.server.CommandNames.Open, arguments: { file: file2.path, fileContent: file2.content, @@ -199,7 +202,7 @@ describe("unittests:: tsserver:: Inferred projects", () => { session.executeCommand({ seq: 5, type: "request", - command: ts.projectSystem.CommandNames.Open, + command: ts.server.CommandNames.Open, arguments: { file: file3.path, fileContent: file3.content, @@ -210,7 +213,7 @@ describe("unittests:: tsserver:: Inferred projects", () => { session.executeCommand({ seq: 6, type: "request", - command: ts.projectSystem.CommandNames.Open, + command: ts.server.CommandNames.Open, arguments: { file: file4.path, fileContent: file4.content, @@ -219,29 +222,29 @@ describe("unittests:: tsserver:: Inferred projects", () => { } as ts.server.protocol.OpenRequest); const projectService = session.getProjectService(); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 3 }); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[0], [file4.path]); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[1], [file1.path, file2.path]); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[2], [file3.path]); + checkNumberOfProjects(projectService, { inferredProjects: 3 }); + checkProjectActualFiles(projectService.inferredProjects[0], [file4.path]); + checkProjectActualFiles(projectService.inferredProjects[1], [file1.path, file2.path]); + checkProjectActualFiles(projectService.inferredProjects[2], [file3.path]); assert.equal(projectService.inferredProjects[0].getCompilationSettings().target, ts.ScriptTarget.ESNext); assert.equal(projectService.inferredProjects[1].getCompilationSettings().target, ts.ScriptTarget.ESNext); assert.equal(projectService.inferredProjects[2].getCompilationSettings().target, ts.ScriptTarget.ES2015); }); - function checkInferredProject(inferredProject: ts.server.InferredProject, actualFiles: ts.projectSystem.File[], target: ts.ScriptTarget) { - ts.projectSystem.checkProjectActualFiles(inferredProject, actualFiles.map(f => f.path)); + function checkInferredProject(inferredProject: ts.server.InferredProject, actualFiles: File[], target: ts.ScriptTarget) { + checkProjectActualFiles(inferredProject, actualFiles.map(f => f.path)); assert.equal(inferredProject.getCompilationSettings().target, target); } function verifyProjectRootWithCaseSensitivity(useCaseSensitiveFileNames: boolean) { - const files: [ts.projectSystem.File, ts.projectSystem.File, ts.projectSystem.File, ts.projectSystem.File] = [ + const files: [File, File, File, File] = [ { path: "/a/file1.ts", content: "let x = 1;" }, { path: "/A/file2.ts", content: "let y = 2;" }, { path: "/b/file2.ts", content: "let x = 3;" }, { path: "/c/file3.ts", content: "let z = 4;" } ]; - const host = ts.projectSystem.createServerHost(files, { useCaseSensitiveFileNames }); - const projectService = ts.projectSystem.createProjectService(host, { useSingleInferredProject: true, useInferredProjectPerProjectRoot: true }); + const host = createServerHost(files, { useCaseSensitiveFileNames }); + const projectService = createProjectService(host, { useSingleInferredProject: true, useInferredProjectPerProjectRoot: true }); projectService.setCompilerOptionsForInferredProjects({ allowJs: true, target: ts.ScriptTarget.ESNext @@ -318,8 +321,8 @@ describe("unittests:: tsserver:: Inferred projects", () => { files.forEach(file => projectService.closeClientFile(file.path)); } - function verifyInferredProjectsState(expected: [ts.projectSystem.File[], ts.ScriptTarget][]) { - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: expected.length }); + function verifyInferredProjectsState(expected: [File[], ts.ScriptTarget][]) { + checkNumberOfProjects(projectService, { inferredProjects: expected.length }); projectService.inferredProjects.forEach((p, index) => { const [actualFiles, target] = expected[index]; checkInferredProject(p, actualFiles, target); @@ -336,24 +339,24 @@ describe("unittests:: tsserver:: Inferred projects", () => { }); it("should still retain configured project created while opening the file", () => { - const appFile: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/app.ts`, + const appFile: File = { + path: `/user/username/projects/myproject/app.ts`, content: `const app = 20;` }; - const config: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/tsconfig.json`, + const config: File = { + path: `/user/username/projects/myproject/tsconfig.json`, content: "{}" }; - const jsFile1: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/jsFile1.js`, + const jsFile1: File = { + path: `/user/username/projects/myproject/jsFile1.js`, content: `const jsFile1 = 10;` }; - const jsFile2: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/jsFile2.js`, + const jsFile2: File = { + path: `/user/username/projects/myproject/jsFile2.js`, content: `const jsFile2 = 10;` }; - const host = ts.projectSystem.createServerHost([appFile, ts.projectSystem.libFile, config, jsFile1, jsFile2]); - const projectService = ts.projectSystem.createProjectService(host); + const host = createServerHost([appFile, libFile, config, jsFile1, jsFile2]); + const projectService = createProjectService(host); const originalSet = projectService.configuredProjects.set; const originalDelete = projectService.configuredProjects.delete; const configuredCreated = new ts.Map(); @@ -371,34 +374,34 @@ describe("unittests:: tsserver:: Inferred projects", () => { // Do not remove config project when opening jsFile that is not present as part of config project projectService.openClientFile(jsFile1.path); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 1, configuredProjects: 1 }); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[0], [jsFile1.path, ts.projectSystem.libFile.path]); + checkNumberOfProjects(projectService, { inferredProjects: 1, configuredProjects: 1 }); + checkProjectActualFiles(projectService.inferredProjects[0], [jsFile1.path, libFile.path]); const project = projectService.configuredProjects.get(config.path)!; - ts.projectSystem.checkProjectActualFiles(project, [appFile.path, config.path, ts.projectSystem.libFile.path]); + checkProjectActualFiles(project, [appFile.path, config.path, libFile.path]); checkConfiguredProjectCreatedAndNotDeleted(); // Do not remove config project when opening jsFile that is not present as part of config project projectService.closeClientFile(jsFile1.path); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 1, configuredProjects: 1 }); + checkNumberOfProjects(projectService, { inferredProjects: 1, configuredProjects: 1 }); projectService.openClientFile(jsFile2.path); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 1, configuredProjects: 1 }); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[0], [jsFile2.path, ts.projectSystem.libFile.path]); - ts.projectSystem.checkProjectActualFiles(project, [appFile.path, config.path, ts.projectSystem.libFile.path]); + checkNumberOfProjects(projectService, { inferredProjects: 1, configuredProjects: 1 }); + checkProjectActualFiles(projectService.inferredProjects[0], [jsFile2.path, libFile.path]); + checkProjectActualFiles(project, [appFile.path, config.path, libFile.path]); checkConfiguredProjectNotCreatedAndNotDeleted(); // Do not remove config project when opening jsFile that is not present as part of config project projectService.openClientFile(jsFile1.path); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 2, configuredProjects: 1 }); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[0], [jsFile2.path, ts.projectSystem.libFile.path]); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[1], [jsFile1.path, ts.projectSystem.libFile.path]); - ts.projectSystem.checkProjectActualFiles(project, [appFile.path, config.path, ts.projectSystem.libFile.path]); + checkNumberOfProjects(projectService, { inferredProjects: 2, configuredProjects: 1 }); + checkProjectActualFiles(projectService.inferredProjects[0], [jsFile2.path, libFile.path]); + checkProjectActualFiles(projectService.inferredProjects[1], [jsFile1.path, libFile.path]); + checkProjectActualFiles(project, [appFile.path, config.path, libFile.path]); checkConfiguredProjectNotCreatedAndNotDeleted(); // When opening file that doesnt fall back to the config file, we remove the config project - projectService.openClientFile(ts.projectSystem.libFile.path); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 2 }); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[0], [jsFile2.path, ts.projectSystem.libFile.path]); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[1], [jsFile1.path, ts.projectSystem.libFile.path]); + projectService.openClientFile(libFile.path); + checkNumberOfProjects(projectService, { inferredProjects: 2 }); + checkProjectActualFiles(projectService.inferredProjects[0], [jsFile2.path, libFile.path]); + checkProjectActualFiles(projectService.inferredProjects[1], [jsFile1.path, libFile.path]); checkConfiguredProjectNotCreatedButDeleted(); function checkConfiguredProjectCreatedAndNotDeleted() { @@ -423,15 +426,15 @@ describe("unittests:: tsserver:: Inferred projects", () => { it("regression test - should infer typeAcquisition for inferred projects when set undefined", () => { const file1 = { path: "/a/file1.js", content: "" }; - const host = ts.projectSystem.createServerHost([file1]); + const host = createServerHost([file1]); - const projectService = ts.projectSystem.createProjectService(host); + const projectService = createProjectService(host); projectService.openClientFile(file1.path); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 1 }); + checkNumberOfProjects(projectService, { inferredProjects: 1 }); const inferredProject = projectService.inferredProjects[0]; - ts.projectSystem.checkProjectActualFiles(inferredProject, [file1.path]); + checkProjectActualFiles(inferredProject, [file1.path]); inferredProject.setTypeAcquisition(undefined); const expected = { @@ -443,8 +446,8 @@ describe("unittests:: tsserver:: Inferred projects", () => { }); it("Setting compiler options for inferred projects when there are no open files should not schedule any refresh", () => { - const host = ts.projectSystem.createServerHost([ts.projectSystem.commonFile1, ts.projectSystem.libFile]); - const projectService = ts.projectSystem.createProjectService(host); + const host = createServerHost([commonFile1, libFile]); + const projectService = createProjectService(host); projectService.setCompilerOptionsForInferredProjects({ allowJs: true, target: ts.ScriptTarget.ES2015 diff --git a/src/testRunner/unittests/tsserver/inlayHints.ts b/src/testRunner/unittests/tsserver/inlayHints.ts index d5e41272ccd..3e658a06990 100644 --- a/src/testRunner/unittests/tsserver/inlayHints.ts +++ b/src/testRunner/unittests/tsserver/inlayHints.ts @@ -1,24 +1,27 @@ import * as ts from "../../_namespaces/ts"; +import { createServerHost, File, libFile } from "../virtualFileSystemWithWatch"; +import { commonFile1, commonFile2 } from "../tscWatch/helpers"; +import { createSession, TestSession } from "./helpers"; describe("unittests:: tsserver:: inlayHints", () => { - const configFile: ts.projectSystem.File = { + const configFile: File = { path: "/a/b/tsconfig.json", content: "{}" }; - const app: ts.projectSystem.File = { + const app: File = { path: "/a/b/app.ts", content: "declare function foo(param: any): void;\nfoo(12);" }; it("with updateOpen request does not corrupt documents", () => { - const host = ts.projectSystem.createServerHost([app, ts.projectSystem.commonFile1, ts.projectSystem.commonFile2, ts.projectSystem.libFile, configFile]); - const session = ts.projectSystem.createSession(host); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Open, + const host = createServerHost([app, commonFile1, commonFile2, libFile, configFile]); + const session = createSession(host); + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Open, arguments: { file: app.path } }); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Configure, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Configure, arguments: { preferences: { includeInlayParameterNameHints: "all" @@ -26,33 +29,33 @@ describe("unittests:: tsserver:: inlayHints", () => { } }); verifyInlayHintResponse(session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.UpdateOpen, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.UpdateOpen, arguments: { changedFiles: [{ fileName: app.path, textChanges: [{ start: { line: 1, offset: 39 }, end: { line: 1, offset: 39 }, newText: "//" }] }] } }); verifyInlayHintResponse(session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.UpdateOpen, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.UpdateOpen, arguments: { changedFiles: [{ fileName: app.path, textChanges: [{ start: { line: 1, offset: 41 }, end: { line: 1, offset: 41 }, newText: "c" }] }] } }); verifyInlayHintResponse(session); - function verifyInlayHintResponse(session: ts.projectSystem.TestSession) { - verifyParamInlayHint(session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.ProvideInlayHints, + function verifyInlayHintResponse(session: TestSession) { + verifyParamInlayHint(session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.ProvideInlayHints, arguments: { file: app.path, start: 0, length: app.content.length, } - }).response as ts.projectSystem.protocol.InlayHintItem[] | undefined); + }).response as ts.server.protocol.InlayHintItem[] | undefined); } - function verifyParamInlayHint(response: ts.projectSystem.protocol.InlayHintItem[] | undefined) { + function verifyParamInlayHint(response: ts.server.protocol.InlayHintItem[] | undefined) { ts.Debug.assert(response); ts.Debug.assert(response[0]); ts.Debug.assertEqual(response[0].text, "param:"); diff --git a/src/testRunner/unittests/tsserver/jsdocTag.ts b/src/testRunner/unittests/tsserver/jsdocTag.ts index ec0c44b1e16..568475465a5 100644 --- a/src/testRunner/unittests/tsserver/jsdocTag.ts +++ b/src/testRunner/unittests/tsserver/jsdocTag.ts @@ -1,7 +1,9 @@ import * as ts from "../../_namespaces/ts"; +import { createServerHost, File } from "../virtualFileSystemWithWatch"; +import { createSession, openFilesForSession } from "./helpers"; describe("unittests:: tsserver:: jsdoc @link ", () => { - const config: ts.projectSystem.File = { + const config: File = { path: "/a/tsconfig.json", content: `{ "compilerOptions": { @@ -12,26 +14,26 @@ describe("unittests:: tsserver:: jsdoc @link ", () => { } ` }; - function assertQuickInfoJSDoc(file: ts.projectSystem.File, options: { + function assertQuickInfoJSDoc(file: File, options: { displayPartsForJSDoc: boolean, - command: ts.projectSystem.protocol.CommandTypes, + command: ts.server.protocol.CommandTypes, tags: string | unknown[] | undefined, documentation: string | unknown[] }) { const { command, displayPartsForJSDoc, tags, documentation } = options; - const session = ts.projectSystem.createSession(ts.projectSystem.createServerHost([file, config])); + const session = createSession(createServerHost([file, config])); session.getProjectService().setHostConfiguration({ preferences: { displayPartsForJSDoc } }); - ts.projectSystem.openFilesForSession([file], session); + openFilesForSession([file], session); const indexOfX = file.content.indexOf("x"); - const quickInfo = session.executeCommandSeq({ - command: command as ts.projectSystem.protocol.CommandTypes.Quickinfo, + const quickInfo = session.executeCommandSeq({ + command: command as ts.server.protocol.CommandTypes.Quickinfo, arguments: { file: file.path, position: indexOfX, - } as ts.projectSystem.protocol.FileLocationRequestArgs + } as ts.server.protocol.FileLocationRequestArgs }).response; - const summaryAndLocation = command === ts.projectSystem.protocol.CommandTypes.Quickinfo ? { + const summaryAndLocation = command === ts.server.protocol.CommandTypes.Quickinfo ? { displayString: "var x: number", start: { line: 3, @@ -75,13 +77,13 @@ describe("unittests:: tsserver:: jsdoc @link ", () => { }); } - const linkInTag: ts.projectSystem.File = { + const linkInTag: File = { path: "/a/someFile1.js", content: `class C { } /** @wat {@link C} */ var x = 1` }; - const linkInComment: ts.projectSystem.File = { + const linkInComment: File = { path: "/a/someFile1.js", content: `class C { } /** {@link C} */ @@ -91,7 +93,7 @@ var x = 1 it("for quickinfo, should provide display parts plus a span for a working link in a tag", () => { assertQuickInfoJSDoc(linkInTag, { - command: ts.projectSystem.protocol.CommandTypes.Quickinfo, + command: ts.server.protocol.CommandTypes.Quickinfo, displayPartsForJSDoc: true, documentation: [], tags: [{ @@ -125,7 +127,7 @@ var x = 1 }); it("for quickinfo, should provide a string for a working link in a tag", () => { assertQuickInfoJSDoc(linkInTag, { - command: ts.projectSystem.protocol.CommandTypes.Quickinfo, + command: ts.server.protocol.CommandTypes.Quickinfo, displayPartsForJSDoc: false, documentation: "", tags: [{ @@ -136,7 +138,7 @@ var x = 1 }); it("for quickinfo, should provide display parts for a working link in a comment", () => { assertQuickInfoJSDoc(linkInComment, { - command: ts.projectSystem.protocol.CommandTypes.Quickinfo, + command: ts.server.protocol.CommandTypes.Quickinfo, displayPartsForJSDoc: true, documentation: [{ kind: "text", @@ -167,7 +169,7 @@ var x = 1 }); it("for quickinfo, should provide a string for a working link in a comment", () => { assertQuickInfoJSDoc(linkInComment, { - command: ts.projectSystem.protocol.CommandTypes.Quickinfo, + command: ts.server.protocol.CommandTypes.Quickinfo, displayPartsForJSDoc: false, documentation: "{@link C}", tags: [], @@ -176,7 +178,7 @@ var x = 1 it("for quickinfo-full, should provide display parts plus a span for a working link in a tag", () => { assertQuickInfoJSDoc(linkInTag, { - command: ts.projectSystem.protocol.CommandTypes.QuickinfoFull, + command: ts.server.protocol.CommandTypes.QuickinfoFull, displayPartsForJSDoc: true, documentation: [], tags: [{ @@ -206,7 +208,7 @@ var x = 1 }); it("for quickinfo-full, should provide a string for a working link in a tag", () => { assertQuickInfoJSDoc(linkInTag, { - command: ts.projectSystem.protocol.CommandTypes.QuickinfoFull, + command: ts.server.protocol.CommandTypes.QuickinfoFull, displayPartsForJSDoc: false, documentation: [], tags: [{ @@ -217,7 +219,7 @@ var x = 1 }); it("for quickinfo-full, should provide display parts plus a span for a working link in a comment", () => { assertQuickInfoJSDoc(linkInComment, { - command: ts.projectSystem.protocol.CommandTypes.QuickinfoFull, + command: ts.server.protocol.CommandTypes.QuickinfoFull, displayPartsForJSDoc: true, documentation: [{ kind: "text", @@ -244,7 +246,7 @@ var x = 1 }); it("for quickinfo-full, should provide a string for a working link in a comment", () => { assertQuickInfoJSDoc(linkInComment, { - command: ts.projectSystem.protocol.CommandTypes.QuickinfoFull, + command: ts.server.protocol.CommandTypes.QuickinfoFull, displayPartsForJSDoc: false, documentation: [{ kind: "text", @@ -272,11 +274,11 @@ var x = 1 function assertSignatureHelpJSDoc(options: { displayPartsForJSDoc: boolean, - command: ts.projectSystem.protocol.CommandTypes, + command: ts.server.protocol.CommandTypes, documentation: string | unknown[], tags: unknown[] }) { - const linkInParamTag: ts.projectSystem.File = { + const linkInParamTag: File = { path: "/a/someFile1.js", content: `class C { } /** @param y - {@link C} */ @@ -285,21 +287,21 @@ x(1)` }; const { command, displayPartsForJSDoc, documentation, tags } = options; - const session = ts.projectSystem.createSession(ts.projectSystem.createServerHost([linkInParamTag, config])); + const session = createSession(createServerHost([linkInParamTag, config])); session.getProjectService().setHostConfiguration({ preferences: { displayPartsForJSDoc } }); - ts.projectSystem.openFilesForSession([linkInParamTag], session); + openFilesForSession([linkInParamTag], session); const indexOfX = linkInParamTag.content.lastIndexOf("1"); - const signatureHelp = session.executeCommandSeq({ - command: command as ts.projectSystem.protocol.CommandTypes.SignatureHelp, + const signatureHelp = session.executeCommandSeq({ + command: command as ts.server.protocol.CommandTypes.SignatureHelp, arguments: { triggerReason: { kind: "invoked" }, file: linkInParamTag.path, position: indexOfX, - } as ts.projectSystem.protocol.SignatureHelpRequestArgs + } as ts.server.protocol.SignatureHelpRequestArgs }).response; - const applicableSpan = command === ts.projectSystem.protocol.CommandTypes.SignatureHelp ? { + const applicableSpan = command === ts.server.protocol.CommandTypes.SignatureHelp ? { end: { line: 4, offset: 4 @@ -383,7 +385,7 @@ x(1)` } it("for signature help, should provide a string for a working link in a comment", () => { assertSignatureHelpJSDoc({ - command: ts.projectSystem.protocol.CommandTypes.SignatureHelp, + command: ts.server.protocol.CommandTypes.SignatureHelp, displayPartsForJSDoc: false, tags: [{ name: "param", @@ -450,7 +452,7 @@ x(1)` }] }]; assertSignatureHelpJSDoc({ - command: ts.projectSystem.protocol.CommandTypes.SignatureHelp, + command: ts.server.protocol.CommandTypes.SignatureHelp, displayPartsForJSDoc: true, tags, documentation: tags[0].text.slice(2) @@ -458,7 +460,7 @@ x(1)` }); it("for signature help-full, should provide a string for a working link in a comment", () => { assertSignatureHelpJSDoc({ - command: ts.projectSystem.protocol.CommandTypes.SignatureHelpFull, + command: ts.server.protocol.CommandTypes.SignatureHelpFull, displayPartsForJSDoc: false, tags: [{ name: "param", @@ -517,7 +519,7 @@ x(1)` }] }]; assertSignatureHelpJSDoc({ - command: ts.projectSystem.protocol.CommandTypes.SignatureHelpFull, + command: ts.server.protocol.CommandTypes.SignatureHelpFull, displayPartsForJSDoc: true, tags, documentation: tags[0].text.slice(2), @@ -526,10 +528,10 @@ x(1)` function assertCompletionsJSDoc(options: { displayPartsForJSDoc: boolean, - command: ts.projectSystem.protocol.CommandTypes, + command: ts.server.protocol.CommandTypes, tags: unknown[] }) { - const linkInParamJSDoc: ts.projectSystem.File = { + const linkInParamJSDoc: File = { path: "/a/someFile1.js", content: `class C { } /** @param x - see {@link C} */ @@ -537,17 +539,17 @@ function foo (x) { } foo` }; const { command, displayPartsForJSDoc, tags } = options; - const session = ts.projectSystem.createSession(ts.projectSystem.createServerHost([linkInParamJSDoc, config])); + const session = createSession(createServerHost([linkInParamJSDoc, config])); session.getProjectService().setHostConfiguration({ preferences: { displayPartsForJSDoc } }); - ts.projectSystem.openFilesForSession([linkInParamJSDoc], session); + openFilesForSession([linkInParamJSDoc], session); const indexOfFoo = linkInParamJSDoc.content.lastIndexOf("fo"); - const completions = session.executeCommandSeq({ - command: command as ts.projectSystem.protocol.CommandTypes.CompletionDetails, + const completions = session.executeCommandSeq({ + command: command as ts.server.protocol.CommandTypes.CompletionDetails, arguments: { entryNames: ["foo"], file: linkInParamJSDoc.path, position: indexOfFoo, - } as ts.projectSystem.protocol.CompletionDetailsRequestArgs + } as ts.server.protocol.CompletionDetailsRequestArgs }).response; assert.deepEqual(completions, [{ codeActions: undefined, @@ -599,7 +601,7 @@ foo` } it("for completions, should provide display parts for a working link in a comment", () => { assertCompletionsJSDoc({ - command: ts.projectSystem.protocol.CommandTypes.CompletionDetails, + command: ts.server.protocol.CommandTypes.CompletionDetails, displayPartsForJSDoc: true, tags: [{ name: "param", @@ -638,7 +640,7 @@ foo` }); it("for completions, should provide a string for a working link in a comment", () => { assertCompletionsJSDoc({ - command: ts.projectSystem.protocol.CommandTypes.CompletionDetails, + command: ts.server.protocol.CommandTypes.CompletionDetails, displayPartsForJSDoc: false, tags: [{ name: "param", @@ -648,7 +650,7 @@ foo` }); it("for completions-full, should provide display parts for a working link in a comment", () => { assertCompletionsJSDoc({ - command: ts.projectSystem.protocol.CommandTypes.CompletionDetailsFull, + command: ts.server.protocol.CommandTypes.CompletionDetailsFull, displayPartsForJSDoc: true, tags: [{ name: "param", @@ -683,7 +685,7 @@ foo` }); it("for completions-full, should provide a string for a working link in a comment", () => { assertCompletionsJSDoc({ - command: ts.projectSystem.protocol.CommandTypes.CompletionDetailsFull, + command: ts.server.protocol.CommandTypes.CompletionDetailsFull, displayPartsForJSDoc: false, tags: [{ name: "param", diff --git a/src/testRunner/unittests/tsserver/languageService.ts b/src/testRunner/unittests/tsserver/languageService.ts index 5353b73ccdc..537f84f44b0 100644 --- a/src/testRunner/unittests/tsserver/languageService.ts +++ b/src/testRunner/unittests/tsserver/languageService.ts @@ -1,5 +1,7 @@ import * as ts from "../../_namespaces/ts"; import * as Utils from "../../_namespaces/Utils"; +import { createServerHost } from "../virtualFileSystemWithWatch"; +import { createProjectService } from "./helpers"; describe("unittests:: tsserver:: languageService", () => { it("should work correctly on case-sensitive file systems", () => { @@ -11,8 +13,8 @@ describe("unittests:: tsserver:: languageService", () => { path: "/a/b/app.ts", content: "let x = 1;" }; - const host = ts.projectSystem.createServerHost([lib, f], { executingFilePath: "/a/Lib/tsc.js", useCaseSensitiveFileNames: true }); - const projectService = ts.projectSystem.createProjectService(host); + const host = createServerHost([lib, f], { executingFilePath: "/a/Lib/tsc.js", useCaseSensitiveFileNames: true }); + const projectService = createProjectService(host); projectService.openClientFile(f.path); projectService.checkNumberOfProjects({ inferredProjects: 1 }); projectService.inferredProjects[0].getLanguageService().getProgram(); @@ -56,8 +58,8 @@ describe("unittests:: tsserver:: languageService", () => { } ]; - const host = ts.projectSystem.createServerHost(files, { executingFilePath: "/project/tsc.js", useCaseSensitiveFileNames: true }); - const projectService = ts.projectSystem.createProjectService(host); + const host = createServerHost(files, { executingFilePath: "/project/tsc.js", useCaseSensitiveFileNames: true }); + const projectService = createProjectService(host); projectService.openClientFile(files[3].path); projectService.openClientFile(files[6].path); projectService.checkNumberOfProjects({ configuredProjects: 2 }); diff --git a/src/testRunner/unittests/tsserver/maxNodeModuleJsDepth.ts b/src/testRunner/unittests/tsserver/maxNodeModuleJsDepth.ts index 928ec383d4f..b3588e9bd44 100644 --- a/src/testRunner/unittests/tsserver/maxNodeModuleJsDepth.ts +++ b/src/testRunner/unittests/tsserver/maxNodeModuleJsDepth.ts @@ -1,18 +1,20 @@ import * as ts from "../../_namespaces/ts"; +import { createServerHost, File, libFile } from "../virtualFileSystemWithWatch"; +import { createProjectService, checkNumberOfInferredProjects } from "./helpers"; describe("unittests:: tsserver:: maxNodeModuleJsDepth for inferred projects", () => { it("should be set to 2 if the project has js root files", () => { - const file1: ts.projectSystem.File = { + const file1: File = { path: "/a/b/file1.js", content: `var t = require("test"); t.` }; - const moduleFile: ts.projectSystem.File = { + const moduleFile: File = { path: "/a/b/node_modules/test/index.js", content: `var v = 10; module.exports = v;` }; - const host = ts.projectSystem.createServerHost([file1, moduleFile]); - const projectService = ts.projectSystem.createProjectService(host); + const host = createServerHost([file1, moduleFile]); + const projectService = createProjectService(host); projectService.openClientFile(file1.path); let project = projectService.inferredProjects[0]; @@ -36,11 +38,11 @@ describe("unittests:: tsserver:: maxNodeModuleJsDepth for inferred projects", () content: "let x =1;" }; - const host = ts.projectSystem.createServerHost([file1, file2, ts.projectSystem.libFile]); - const projectService = ts.projectSystem.createProjectService(host, { useSingleInferredProject: true }); + const host = createServerHost([file1, file2, libFile]); + const projectService = createProjectService(host, { useSingleInferredProject: true }); projectService.openClientFile(file1.path); - ts.projectSystem.checkNumberOfInferredProjects(projectService, 1); + checkNumberOfInferredProjects(projectService, 1); let project = projectService.inferredProjects[0]; assert.isUndefined(project.getCompilationSettings().maxNodeModuleJsDepth); diff --git a/src/testRunner/unittests/tsserver/metadataInResponse.ts b/src/testRunner/unittests/tsserver/metadataInResponse.ts index 35d3081ebc6..81fb935298f 100644 --- a/src/testRunner/unittests/tsserver/metadataInResponse.ts +++ b/src/testRunner/unittests/tsserver/metadataInResponse.ts @@ -1,15 +1,17 @@ import * as ts from "../../_namespaces/ts"; import * as Harness from "../../_namespaces/Harness"; +import { createServerHost, File, TestServerHost } from "../virtualFileSystemWithWatch"; +import { mapOutputToJson, TestSession, createSession, openFilesForSession } from "./helpers"; describe("unittests:: tsserver:: with metadata in response", () => { const metadata = "Extra Info"; - function verifyOutput(host: ts.projectSystem.TestServerHost, expectedResponse: ts.projectSystem.protocol.Response) { - const output = host.getOutput().map(ts.projectSystem.mapOutputToJson); + function verifyOutput(host: TestServerHost, expectedResponse: ts.server.protocol.Response) { + const output = host.getOutput().map(mapOutputToJson); assert.deepEqual(output, [expectedResponse]); host.clearOutput(); } - function verifyCommandWithMetadata(session: ts.projectSystem.TestSession, host: ts.projectSystem.TestServerHost, command: Partial, expectedResponseBody: U) { + function verifyCommandWithMetadata(session: TestSession, host: TestServerHost, command: Partial, expectedResponseBody: U) { command.seq = session.getSeq(); command.type = "request"; session.onMessage(JSON.stringify(command)); @@ -19,15 +21,15 @@ describe("unittests:: tsserver:: with metadata in response", () => { ); } - const aTs: ts.projectSystem.File = { path: "/a.ts", content: `class c { prop = "hello"; foo() { return this.prop; } }` }; - const tsconfig: ts.projectSystem.File = { + const aTs: File = { path: "/a.ts", content: `class c { prop = "hello"; foo() { return this.prop; } }` }; + const tsconfig: File = { path: "/tsconfig.json", content: JSON.stringify({ compilerOptions: { plugins: [{ name: "myplugin" }] } }) }; - function createHostWithPlugin(files: readonly ts.projectSystem.File[]) { - const host = ts.projectSystem.createServerHost(files); + function createHostWithPlugin(files: readonly File[]) { + const host = createServerHost(files); host.require = (_initialPath, moduleName) => { assert.equal(moduleName, "myplugin"); return { @@ -51,32 +53,32 @@ describe("unittests:: tsserver:: with metadata in response", () => { } describe("With completion requests", () => { - const completionRequestArgs: ts.projectSystem.protocol.CompletionsRequestArgs = { + const completionRequestArgs: ts.server.protocol.CompletionsRequestArgs = { file: aTs.path, line: 1, offset: aTs.content.indexOf("this.") + 1 + "this.".length }; - const expectedCompletionEntries: readonly ts.projectSystem.protocol.CompletionEntry[] = [ + const expectedCompletionEntries: readonly ts.server.protocol.CompletionEntry[] = [ { name: "foo", kind: ts.ScriptElementKind.memberFunctionElement, kindModifiers: "", sortText: ts.Completions.SortText.LocationPriority }, { name: "prop", kind: ts.ScriptElementKind.memberVariableElement, kindModifiers: "", sortText: ts.Completions.SortText.LocationPriority } ]; it("can pass through metadata when the command returns array", () => { const host = createHostWithPlugin([aTs, tsconfig]); - const session = ts.projectSystem.createSession(host); - ts.projectSystem.openFilesForSession([aTs], session); - verifyCommandWithMetadata(session, host, { - command: ts.projectSystem.protocol.CommandTypes.Completions, + const session = createSession(host); + openFilesForSession([aTs], session); + verifyCommandWithMetadata(session, host, { + command: ts.server.protocol.CommandTypes.Completions, arguments: completionRequestArgs }, expectedCompletionEntries); }); it("can pass through metadata when the command returns object", () => { const host = createHostWithPlugin([aTs, tsconfig]); - const session = ts.projectSystem.createSession(host); - ts.projectSystem.openFilesForSession([aTs], session); - verifyCommandWithMetadata(session, host, { - command: ts.projectSystem.protocol.CommandTypes.CompletionInfo, + const session = createSession(host); + openFilesForSession([aTs], session); + verifyCommandWithMetadata(session, host, { + command: ts.server.protocol.CommandTypes.CompletionInfo, arguments: completionRequestArgs }, { flags: 0, @@ -92,12 +94,12 @@ describe("unittests:: tsserver:: with metadata in response", () => { }); it("returns undefined correctly", () => { - const aTs: ts.projectSystem.File = { path: "/a.ts", content: `class c { prop = "hello"; foo() { const x = 0; } }` }; + const aTs: File = { path: "/a.ts", content: `class c { prop = "hello"; foo() { const x = 0; } }` }; const host = createHostWithPlugin([aTs, tsconfig]); - const session = ts.projectSystem.createSession(host); - ts.projectSystem.openFilesForSession([aTs], session); - verifyCommandWithMetadata(session, host, { - command: ts.projectSystem.protocol.CommandTypes.Completions, + const session = createSession(host); + openFilesForSession([aTs], session); + verifyCommandWithMetadata(session, host, { + command: ts.server.protocol.CommandTypes.Completions, arguments: { file: aTs.path, line: 1, offset: aTs.content.indexOf("x") + 1 } }, /*expectedResponseBody*/ undefined); }); diff --git a/src/testRunner/unittests/tsserver/moduleResolution.ts b/src/testRunner/unittests/tsserver/moduleResolution.ts index 0ff53167e26..2c755491135 100644 --- a/src/testRunner/unittests/tsserver/moduleResolution.ts +++ b/src/testRunner/unittests/tsserver/moduleResolution.ts @@ -1,11 +1,12 @@ -import * as ts from "../../_namespaces/ts"; import * as Utils from "../../_namespaces/Utils"; +import { createServerHost, File, libFile } from "../virtualFileSystemWithWatch"; +import { createSession, createLoggerWithInMemoryLogs, openFilesForSession, verifyGetErrRequest, baselineTsserverLogs } from "./helpers"; describe("unittests:: tsserver:: moduleResolution", () => { describe("package json file is edited", () => { function setup(packageFileContents: string) { - const configFile: ts.projectSystem.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", @@ -15,30 +16,30 @@ describe("unittests:: tsserver:: moduleResolution", () => { } }) }; - const packageFile: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/package.json`, + const packageFile: File = { + path: `/user/username/projects/myproject/package.json`, content: packageFileContents }; - const fileA: ts.projectSystem.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.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/src/fileB.mts`, + const fileB: File = { + path: `/user/username/projects/myproject/src/fileB.mts`, content: Utils.dedent` export function foo() { } ` }; - const host = ts.projectSystem.createServerHost([configFile, fileA, fileB, packageFile, { ...ts.projectSystem.libFile, path: "/a/lib/lib.es2016.full.d.ts" }]); - const session = ts.projectSystem.createSession(host, { canUseEvents: true, logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([fileA], session); + const host = createServerHost([configFile, fileA, fileB, packageFile, { ...libFile, path: "/a/lib/lib.es2016.full.d.ts" }]); + const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([fileA], session); return { host, session, packageFile, - verifyErr: () => ts.projectSystem.verifyGetErrRequest({ files: [fileA], session, host }), + verifyErr: () => verifyGetErrRequest({ files: [fileA], session, host }), }; } it("package json file is edited", () => { @@ -78,7 +79,7 @@ describe("unittests:: tsserver:: moduleResolution", () => { host.runQueuedTimeoutCallbacks(); // Actual update verifyErr(); - ts.projectSystem.baselineTsserverLogs("moduleResolution", "package json file is edited", session); + baselineTsserverLogs("moduleResolution", "package json file is edited", session); }); it("package json file is edited when package json with type module exists", () => { @@ -116,7 +117,7 @@ describe("unittests:: tsserver:: moduleResolution", () => { host.runQueuedTimeoutCallbacks(); // Actual update verifyErr(); - ts.projectSystem.baselineTsserverLogs("moduleResolution", "package json file is edited when package json with type module exists", session); + baselineTsserverLogs("moduleResolution", "package json file is edited when package json with type module exists", session); }); }); }); \ No newline at end of file diff --git a/src/testRunner/unittests/tsserver/moduleSpecifierCache.ts b/src/testRunner/unittests/tsserver/moduleSpecifierCache.ts index 59d05ef1a9b..4151e78e7a8 100644 --- a/src/testRunner/unittests/tsserver/moduleSpecifierCache.ts +++ b/src/testRunner/unittests/tsserver/moduleSpecifierCache.ts @@ -1,38 +1,40 @@ import * as ts from "../../_namespaces/ts"; +import { createServerHost, File, SymLink, TestServerHost } from "../virtualFileSystemWithWatch"; +import { createLoggerWithInMemoryLogs, baselineTsserverLogs, executeSessionRequest, Logger, createSession, openFilesForSession, configuredProjectAt } 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: "/src/a.ts", content: "export const foo = 0;", }; -const bTs: ts.projectSystem.File = { +const bTs: File = { path: "/src/b.ts", content: "foo", }; -const cTs: ts.projectSystem.File = { +const cTs: File = { path: "/src/c.ts", content: "import ", }; -const bSymlink: ts.projectSystem.SymLink = { +const bSymlink: SymLink = { path: "/src/b-link.ts", symLink: "./b.ts", }; -const tsconfig: ts.projectSystem.File = { +const tsconfig: File = { path: "/tsconfig.json", content: `{ "include": ["src"] }`, }; -const ambientDeclaration: ts.projectSystem.File = { +const ambientDeclaration: File = { path: "/src/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;" }; @@ -60,13 +62,13 @@ describe("unittests:: tsserver:: moduleSpecifierCache", () => { }); it("invalidates module specifiers when changes happen in contained node_modules directories", () => { - const { host, session, moduleSpecifierCache, triggerCompletions } = setup(host => ts.projectSystem.createLoggerWithInMemoryLogs(host)); + const { host, session, moduleSpecifierCache, triggerCompletions } = setup(host => createLoggerWithInMemoryLogs(host)); // Completion at an import statement will calculate and cache module specifiers triggerCompletions({ file: cTs.path, line: 1, offset: cTs.content.length + 1 }); host.writeFile("/node_modules/.staging/mobx-12345678/package.json", "{}"); host.runQueuedTimeoutCallbacks(); assert.equal(moduleSpecifierCache.count(), 0); - ts.projectSystem.baselineTsserverLogs("moduleSpecifierCache", "invalidates module specifiers when changes happen in contained node_modules directories", session); + baselineTsserverLogs("moduleSpecifierCache", "invalidates module specifiers when changes happen in contained node_modules directories", session); }); it("does not invalidate the cache when new files are added", () => { @@ -102,7 +104,7 @@ describe("unittests:: tsserver:: moduleSpecifierCache", () => { const preferences: ts.UserPreferences = { importModuleSpecifierPreference: "project-relative" }; assert.ok(getWithPreferences({})); - ts.projectSystem.executeSessionRequest(session, ts.projectSystem.protocol.CommandTypes.Configure, { preferences }); + executeSessionRequest(session, ts.server.protocol.CommandTypes.Configure, { preferences }); // Nothing changes yet assert.ok(getWithPreferences({})); assert.isUndefined(getWithPreferences(preferences)); @@ -112,7 +114,7 @@ describe("unittests:: tsserver:: moduleSpecifierCache", () => { assert.ok(getWithPreferences(preferences)); // Test other affecting preference - ts.projectSystem.executeSessionRequest(session, ts.projectSystem.protocol.CommandTypes.Configure, { + executeSessionRequest(session, ts.server.protocol.CommandTypes.Configure, { preferences: { importModuleSpecifierEnding: "js" }, }); triggerCompletions({ file: bTs.path, line: 1, offset: 3 }); @@ -124,13 +126,13 @@ describe("unittests:: tsserver:: moduleSpecifierCache", () => { }); }); -function setup(createLogger?: (host: ts.projectSystem.TestServerHost) => ts.projectSystem.Logger) { - const host = ts.projectSystem.createServerHost([aTs, bTs, cTs, bSymlink, ambientDeclaration, tsconfig, packageJson, mobxPackageJson, mobxDts]); - const session = ts.projectSystem.createSession(host, createLogger && { logger: createLogger(host) }); - ts.projectSystem.openFilesForSession([aTs, bTs, cTs], session); +function setup(createLogger?: (host: TestServerHost) => Logger) { + const host = createServerHost([aTs, bTs, cTs, bSymlink, ambientDeclaration, tsconfig, packageJson, mobxPackageJson, mobxDts]); + const session = createSession(host, createLogger && { logger: createLogger(host) }); + openFilesForSession([aTs, bTs, cTs], session); const projectService = session.getProjectService(); - const project = ts.projectSystem.configuredProjectAt(projectService, 0); - ts.projectSystem.executeSessionRequest(session, ts.projectSystem.protocol.CommandTypes.Configure, { + const project = configuredProjectAt(projectService, 0); + executeSessionRequest(session, ts.server.protocol.CommandTypes.Configure, { preferences: { includeCompletionsForImportStatements: true, includeCompletionsForModuleExports: true, @@ -142,8 +144,8 @@ function setup(createLogger?: (host: ts.projectSystem.TestServerHost) => ts.proj return { host, project, projectService, session, moduleSpecifierCache: project.getModuleSpecifierCache(), triggerCompletions }; - function triggerCompletions(requestLocation: ts.projectSystem.protocol.FileLocationRequestArgs) { - ts.projectSystem.executeSessionRequest(session, ts.projectSystem.protocol.CommandTypes.CompletionInfo, { + function triggerCompletions(requestLocation: ts.server.protocol.FileLocationRequestArgs) { + executeSessionRequest(session, ts.server.protocol.CommandTypes.CompletionInfo, { ...requestLocation, }); } diff --git a/src/testRunner/unittests/tsserver/navTo.ts b/src/testRunner/unittests/tsserver/navTo.ts index 1d181b45510..9c6acda8fd1 100644 --- a/src/testRunner/unittests/tsserver/navTo.ts +++ b/src/testRunner/unittests/tsserver/navTo.ts @@ -1,39 +1,41 @@ import * as ts from "../../_namespaces/ts"; +import { createServerHost, File, libFile } from "../virtualFileSystemWithWatch"; +import { createSession, openFilesForSession, makeSessionRequest, createLoggerWithInMemoryLogs, baselineTsserverLogs } from "./helpers"; describe("unittests:: tsserver:: navigate-to for javascript project", () => { - function findNavToItem(items: ts.projectSystem.protocol.NavtoItem[], itemName: string, itemKind: string) { + function findNavToItem(items: ts.server.protocol.NavtoItem[], itemName: string, itemKind: string) { return ts.find(items, item => item.name === itemName && item.kind === itemKind); } - function containsNavToItem(items: ts.projectSystem.protocol.NavtoItem[], itemName: string, itemKind: string) { + function containsNavToItem(items: ts.server.protocol.NavtoItem[], itemName: string, itemKind: string) { return findNavToItem(items, itemName, itemKind) !== undefined; } it("should not include type symbols", () => { - const file1: ts.projectSystem.File = { + const file1: File = { path: "/a/b/file1.js", content: "function foo() {}" }; - const configFile: ts.projectSystem.File = { + const configFile: File = { path: "/a/b/jsconfig.json", content: "{}" }; - const host = ts.projectSystem.createServerHost([file1, configFile, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host); - ts.projectSystem.openFilesForSession([file1], session); + const host = createServerHost([file1, configFile, libFile]); + const session = createSession(host); + openFilesForSession([file1], session); // Try to find some interface type defined in lib.d.ts - const libTypeNavToRequest = ts.projectSystem.makeSessionRequest(ts.projectSystem.CommandNames.Navto, { searchValue: "Document", file: file1.path, projectFileName: configFile.path }); - const items = session.executeCommand(libTypeNavToRequest).response as ts.projectSystem.protocol.NavtoItem[]; + const libTypeNavToRequest = makeSessionRequest(ts.server.CommandNames.Navto, { searchValue: "Document", file: file1.path, projectFileName: configFile.path }); + const items = session.executeCommand(libTypeNavToRequest).response as ts.server.protocol.NavtoItem[]; assert.isFalse(containsNavToItem(items, "Document", "interface"), `Found lib.d.ts symbol in JavaScript project nav to request result.`); - const localFunctionNavToRequst = ts.projectSystem.makeSessionRequest(ts.projectSystem.CommandNames.Navto, { searchValue: "foo", file: file1.path, projectFileName: configFile.path }); - const items2 = session.executeCommand(localFunctionNavToRequst).response as ts.projectSystem.protocol.NavtoItem[]; + const localFunctionNavToRequst = makeSessionRequest(ts.server.CommandNames.Navto, { searchValue: "foo", file: file1.path, projectFileName: configFile.path }); + const items2 = session.executeCommand(localFunctionNavToRequst).response as ts.server.protocol.NavtoItem[]; assert.isTrue(containsNavToItem(items2, "foo", "function"), `Cannot find function symbol "foo".`); }); it("should de-duplicate symbols", () => { - const configFile1: ts.projectSystem.File = { + const configFile1: File = { path: "/a/tsconfig.json", content: `{ "compilerOptions": { @@ -41,11 +43,11 @@ describe("unittests:: tsserver:: navigate-to for javascript project", () => { } }` }; - const file1: ts.projectSystem.File = { + const file1: File = { path: "/a/index.ts", content: "export const abcdef = 1;" }; - const configFile2: ts.projectSystem.File = { + const configFile2: File = { path: "/b/tsconfig.json", content: `{ "compilerOptions": { @@ -56,30 +58,30 @@ describe("unittests:: tsserver:: navigate-to for javascript project", () => { ] }` }; - const file2: ts.projectSystem.File = { + const file2: File = { path: "/b/index.ts", content: `import a = require("../a"); export const ghijkl = a.abcdef;` }; - const host = ts.projectSystem.createServerHost([configFile1, file1, configFile2, file2]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([file1, file2], session); + const host = createServerHost([configFile1, file1, configFile2, file2]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([file1, file2], session); - const request = ts.projectSystem.makeSessionRequest(ts.projectSystem.CommandNames.Navto, { searchValue: "abcdef", file: file1.path }); - session.executeCommand(request).response as ts.projectSystem.protocol.NavtoItem[]; + const request = makeSessionRequest(ts.server.CommandNames.Navto, { searchValue: "abcdef", file: file1.path }); + session.executeCommand(request).response as ts.server.protocol.NavtoItem[]; - ts.projectSystem.baselineTsserverLogs("navTo", "should de-duplicate symbols", session); + baselineTsserverLogs("navTo", "should de-duplicate symbols", session); }); it("should de-duplicate symbols when searching all projects", () => { - const solutionConfig: ts.projectSystem.File = { + const solutionConfig: File = { path: "/tsconfig.json", content: JSON.stringify({ references: [{ path: "./a" }, { path: "./b" }], files: [], }) }; - const configFile1: ts.projectSystem.File = { + const configFile1: File = { path: "/a/tsconfig.json", content: `{ "compilerOptions": { @@ -87,11 +89,11 @@ export const ghijkl = a.abcdef;` } }` }; - const file1: ts.projectSystem.File = { + const file1: File = { path: "/a/index.ts", content: "export const abcdef = 1;" }; - const configFile2: ts.projectSystem.File = { + const configFile2: File = { path: "/b/tsconfig.json", content: `{ "compilerOptions": { @@ -102,36 +104,36 @@ export const ghijkl = a.abcdef;` ] }` }; - const file2: ts.projectSystem.File = { + const file2: File = { path: "/b/index.ts", content: `import a = require("../a"); export const ghijkl = a.abcdef;` }; - const host = ts.projectSystem.createServerHost([configFile1, file1, configFile2, file2, solutionConfig]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([file1], session); + const host = createServerHost([configFile1, file1, configFile2, file2, solutionConfig]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([file1], session); - const request = ts.projectSystem.makeSessionRequest(ts.projectSystem.CommandNames.Navto, { searchValue: "abcdef" }); - session.executeCommand(request).response as ts.projectSystem.protocol.NavtoItem[]; - ts.projectSystem.baselineTsserverLogs("navTo", "should de-duplicate symbols when searching all projects", session); + const request = makeSessionRequest(ts.server.CommandNames.Navto, { searchValue: "abcdef" }); + session.executeCommand(request).response as ts.server.protocol.NavtoItem[]; + baselineTsserverLogs("navTo", "should de-duplicate symbols when searching all projects", session); }); it("should work with Deprecated", () => { - const file1: ts.projectSystem.File = { + const file1: File = { path: "/a/b/file1.js", content: "/** @deprecated */\nfunction foo () {}" }; - const configFile: ts.projectSystem.File = { + const configFile: File = { path: "/a/b/jsconfig.json", content: "{}" }; - const host = ts.projectSystem.createServerHost([file1, configFile, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host); - ts.projectSystem.openFilesForSession([file1], session); + const host = createServerHost([file1, configFile, libFile]); + const session = createSession(host); + openFilesForSession([file1], session); // Try to find some interface type defined in lib.d.ts - const libTypeNavToRequest = ts.projectSystem.makeSessionRequest(ts.projectSystem.CommandNames.Navto, { searchValue: "foo", file: file1.path, projectFileName: configFile.path }); - const items = session.executeCommand(libTypeNavToRequest).response as ts.projectSystem.protocol.NavtoItem[]; + const libTypeNavToRequest = makeSessionRequest(ts.server.CommandNames.Navto, { searchValue: "foo", file: file1.path, projectFileName: configFile.path }); + const items = session.executeCommand(libTypeNavToRequest).response as ts.server.protocol.NavtoItem[]; const fooItem = findNavToItem(items, "foo", "function"); assert.isNotNull(fooItem, `Cannot find function symbol "foo".`); assert.isTrue(fooItem?.kindModifiers?.includes("deprecated")); diff --git a/src/testRunner/unittests/tsserver/occurences.ts b/src/testRunner/unittests/tsserver/occurences.ts index d7975259162..4d5481e0653 100644 --- a/src/testRunner/unittests/tsserver/occurences.ts +++ b/src/testRunner/unittests/tsserver/occurences.ts @@ -1,44 +1,46 @@ import * as ts from "../../_namespaces/ts"; +import { createServerHost, File } from "../virtualFileSystemWithWatch"; +import { createSession, makeSessionRequest } from "./helpers"; describe("unittests:: tsserver:: occurrence highlight on string", () => { it("should be marked if only on string values", () => { - const file1: ts.projectSystem.File = { + const file1: File = { path: "/a/b/file1.ts", content: `let t1 = "div";\nlet t2 = "div";\nlet t3 = { "div": 123 };\nlet t4 = t3["div"];` }; - const host = ts.projectSystem.createServerHost([file1]); - const session = ts.projectSystem.createSession(host); + const host = createServerHost([file1]); + const session = createSession(host); const projectService = session.getProjectService(); projectService.openClientFile(file1.path); { - const highlightRequest = ts.projectSystem.makeSessionRequest( - ts.projectSystem.CommandNames.Occurrences, + const highlightRequest = makeSessionRequest( + ts.server.CommandNames.Occurrences, { file: file1.path, line: 1, offset: 11 } ); - const highlightResponse = session.executeCommand(highlightRequest).response as ts.projectSystem.protocol.OccurrencesResponseItem[]; + const highlightResponse = session.executeCommand(highlightRequest).response as ts.server.protocol.OccurrencesResponseItem[]; const firstOccurence = highlightResponse[0]; assert.isTrue(firstOccurence.isInString, "Highlights should be marked with isInString"); } { - const highlightRequest = ts.projectSystem.makeSessionRequest( - ts.projectSystem.CommandNames.Occurrences, + const highlightRequest = makeSessionRequest( + ts.server.CommandNames.Occurrences, { file: file1.path, line: 3, offset: 13 } ); - const highlightResponse = session.executeCommand(highlightRequest).response as ts.projectSystem.protocol.OccurrencesResponseItem[]; + const highlightResponse = session.executeCommand(highlightRequest).response as ts.server.protocol.OccurrencesResponseItem[]; assert.isTrue(highlightResponse.length === 2); const firstOccurence = highlightResponse[0]; assert.isUndefined(firstOccurence.isInString, "Highlights should not be marked with isInString if on property name"); } { - const highlightRequest = ts.projectSystem.makeSessionRequest( - ts.projectSystem.CommandNames.Occurrences, + const highlightRequest = makeSessionRequest( + ts.server.CommandNames.Occurrences, { file: file1.path, line: 4, offset: 14 } ); - const highlightResponse = session.executeCommand(highlightRequest).response as ts.projectSystem.protocol.OccurrencesResponseItem[]; + const highlightResponse = session.executeCommand(highlightRequest).response as ts.server.protocol.OccurrencesResponseItem[]; assert.isTrue(highlightResponse.length === 2); const firstOccurence = highlightResponse[0]; assert.isUndefined(firstOccurence.isInString, "Highlights should not be marked with isInString if on indexer"); diff --git a/src/testRunner/unittests/tsserver/openFile.ts b/src/testRunner/unittests/tsserver/openFile.ts index ae8e284d616..998c68cfa50 100644 --- a/src/testRunner/unittests/tsserver/openFile.ts +++ b/src/testRunner/unittests/tsserver/openFile.ts @@ -1,4 +1,6 @@ import * as ts from "../../_namespaces/ts"; +import { createServerHost, File, libFile } from "../virtualFileSystemWithWatch"; +import { createProjectService, toExternalFile, checkProjectActualFiles, createSession, createLoggerWithInMemoryLogs, openFilesForSession, verifyGetErrRequest, protocolTextSpanFromSubstring, baselineTsserverLogs } from "./helpers"; describe("unittests:: tsserver:: Open-file", () => { it("can be reloaded with empty content", () => { @@ -7,10 +9,10 @@ describe("unittests:: tsserver:: Open-file", () => { content: "let x = 1" }; const projectFileName = "externalProject"; - const host = ts.projectSystem.createServerHost([f]); - const projectService = ts.projectSystem.createProjectService(host); + const host = createServerHost([f]); + const projectService = createProjectService(host); // create a project - projectService.openExternalProject({ projectFileName, rootFiles: [ts.projectSystem.toExternalFile(f.path)], options: {} }); + projectService.openExternalProject({ projectFileName, rootFiles: [toExternalFile(f.path)], options: {} }); projectService.checkNumberOfProjects({ externalProjects: 1 }); const p = projectService.externalProjects[0]; @@ -29,26 +31,26 @@ describe("unittests:: tsserver:: Open-file", () => { } function verifyOpenFileWorks(useCaseSensitiveFileNames: boolean) { - const file1: ts.projectSystem.File = { + const file1: File = { path: "/a/b/src/app.ts", content: "let x = 10;" }; - const file2: ts.projectSystem.File = { + const file2: File = { path: "/a/B/lib/module2.ts", content: "let z = 10;" }; - const configFile: ts.projectSystem.File = { + const configFile: File = { path: "/a/b/tsconfig.json", content: "" }; - const configFile2: ts.projectSystem.File = { + const configFile2: File = { path: "/a/tsconfig.json", content: "" }; - const host = ts.projectSystem.createServerHost([file1, file2, configFile, configFile2], { + const host = createServerHost([file1, file2, configFile, configFile2], { useCaseSensitiveFileNames }); - const service = ts.projectSystem.createProjectService(host); + const service = createProjectService(host); // Open file1 -> configFile verifyConfigFileName(file1, "/a", configFile); @@ -60,7 +62,7 @@ describe("unittests:: tsserver:: Open-file", () => { verifyConfigFileName(file2, "/a/b", useCaseSensitiveFileNames ? configFile2 : configFile); verifyConfigFileName(file2, "/a/B", useCaseSensitiveFileNames ? undefined : configFile); - function verifyConfigFileName(file: ts.projectSystem.File, projectRoot: string, expectedConfigFile: ts.projectSystem.File | undefined) { + function verifyConfigFileName(file: File, projectRoot: string, expectedConfigFile: File | undefined) { const { configFileName } = service.openClientFile(file.path, /*fileContent*/ undefined, /*scriptKind*/ undefined, projectRoot); assert.equal(configFileName, expectedConfigFile && expectedConfigFile.path); service.closeClientFile(file.path); @@ -76,21 +78,21 @@ describe("unittests:: tsserver:: Open-file", () => { it("uses existing project even if project refresh is pending", () => { const projectFolder = "/user/someuser/projects/myproject"; - const aFile: ts.projectSystem.File = { + const aFile: File = { path: `${projectFolder}/src/a.ts`, content: "export const x = 0;" }; - const configFile: ts.projectSystem.File = { + const configFile: File = { path: `${projectFolder}/tsconfig.json`, content: "{}" }; - const files = [aFile, configFile, ts.projectSystem.libFile]; - const host = ts.projectSystem.createServerHost(files); - const service = ts.projectSystem.createProjectService(host); + const files = [aFile, configFile, libFile]; + const host = createServerHost(files); + const service = createProjectService(host); service.openClientFile(aFile.path, /*fileContent*/ undefined, ts.ScriptKind.TS, projectFolder); verifyProject(); - const bFile: ts.projectSystem.File = { + const bFile: File = { path: `${projectFolder}/src/b.ts`, content: `export {}; declare module "./a" { export const y: number; }` }; @@ -102,37 +104,37 @@ describe("unittests:: tsserver:: Open-file", () => { function verifyProject() { assert.isDefined(service.configuredProjects.get(configFile.path)); const project = service.configuredProjects.get(configFile.path)!; - ts.projectSystem.checkProjectActualFiles(project, files.map(f => f.path)); + checkProjectActualFiles(project, files.map(f => f.path)); } }); it("can open same file again", () => { const projectFolder = "/user/someuser/projects/myproject"; - const aFile: ts.projectSystem.File = { + const aFile: File = { path: `${projectFolder}/src/a.ts`, content: "export const x = 0;" }; - const configFile: ts.projectSystem.File = { + const configFile: File = { path: `${projectFolder}/tsconfig.json`, content: "{}" }; - const files = [aFile, configFile, ts.projectSystem.libFile]; - const host = ts.projectSystem.createServerHost(files); - const service = ts.projectSystem.createProjectService(host); + const files = [aFile, configFile, libFile]; + const host = createServerHost(files); + const service = createProjectService(host); verifyProject(aFile.content); verifyProject(`${aFile.content}export const y = 10;`); function verifyProject(aFileContent: string) { service.openClientFile(aFile.path, aFileContent, ts.ScriptKind.TS, projectFolder); const project = service.configuredProjects.get(configFile.path)!; - ts.projectSystem.checkProjectActualFiles(project, files.map(f => f.path)); + checkProjectActualFiles(project, files.map(f => f.path)); assert.equal(project.getCurrentProgram()?.getSourceFile(aFile.path)!.text, aFileContent); } }); it("when file makes edits to add/remove comment directives, they are handled correcrly", () => { - 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; function foo() { // @ts-ignore @@ -147,16 +149,16 @@ function bar() { foo(); bar();` }; - const host = ts.projectSystem.createServerHost([file, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { canUseEvents: true, logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([file], session); - ts.projectSystem.verifyGetErrRequest({ session, host, files: [file] }); + const host = createServerHost([file, libFile]); + const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([file], session); + verifyGetErrRequest({ session, host, files: [file] }); // Remove first ts-ignore and check only first error is reported const tsIgnoreComment = `// @ts-ignore`; - const locationOfTsIgnore = ts.projectSystem.protocolTextSpanFromSubstring(file.content, tsIgnoreComment); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.UpdateOpen, + const locationOfTsIgnore = protocolTextSpanFromSubstring(file.content, tsIgnoreComment); + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.UpdateOpen, arguments: { changedFiles: [{ fileName: file.path, @@ -167,10 +169,10 @@ bar();` }] } }); - ts.projectSystem.verifyGetErrRequest({ session, host, files: [file] }); + verifyGetErrRequest({ session, host, files: [file] }); // Revert the change and no errors should be reported - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.UpdateOpen, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.UpdateOpen, arguments: { changedFiles: [{ fileName: file.path, @@ -181,7 +183,7 @@ bar();` }] } }); - ts.projectSystem.verifyGetErrRequest({ session, host, files: [file] }); - ts.projectSystem.baselineTsserverLogs("openfile", "when file makes edits to add/remove comment directives, they are handled correcrly", session); + verifyGetErrRequest({ session, host, files: [file] }); + baselineTsserverLogs("openfile", "when file makes edits to add/remove comment directives, they are handled correcrly", session); }); }); diff --git a/src/testRunner/unittests/tsserver/packageJsonInfo.ts b/src/testRunner/unittests/tsserver/packageJsonInfo.ts index d6bf2116a8c..02de3b01ebc 100644 --- a/src/testRunner/unittests/tsserver/packageJsonInfo.ts +++ b/src/testRunner/unittests/tsserver/packageJsonInfo.ts @@ -1,6 +1,8 @@ import * as ts from "../../_namespaces/ts"; +import { createServerHost, File } from "../virtualFileSystemWithWatch"; +import { createSession, configuredProjectAt } from "./helpers"; -const tsConfig: ts.projectSystem.File = { +const tsConfig: File = { path: "/tsconfig.json", content: "{}" }; @@ -18,7 +20,7 @@ const packageJsonContent = { webpack: "*" } }; -const packageJson: ts.projectSystem.File = { +const packageJson: File = { path: "/package.json", content: JSON.stringify(packageJsonContent, undefined, 2) }; @@ -102,11 +104,11 @@ describe("unittests:: tsserver:: packageJsonInfo", () => { }); }); -function setup(files: readonly ts.projectSystem.File[] = [tsConfig, packageJson]) { - const host = ts.projectSystem.createServerHost(files); - const session = ts.projectSystem.createSession(host); +function setup(files: readonly File[] = [tsConfig, packageJson]) { + const host = createServerHost(files); + const session = createSession(host); const projectService = session.getProjectService(); projectService.openClientFile(files[0].path); - const project = ts.projectSystem.configuredProjectAt(projectService, 0); + const project = configuredProjectAt(projectService, 0); return { host, session, project, projectService }; } diff --git a/src/testRunner/unittests/tsserver/partialSemanticServer.ts b/src/testRunner/unittests/tsserver/partialSemanticServer.ts index 60d4adb1ae4..416ce5c2cec 100644 --- a/src/testRunner/unittests/tsserver/partialSemanticServer.ts +++ b/src/testRunner/unittests/tsserver/partialSemanticServer.ts @@ -1,36 +1,38 @@ import * as ts from "../../_namespaces/ts"; +import { createServerHost, File, libFile } from "../virtualFileSystemWithWatch"; +import { createSession, createLoggerWithInMemoryLogs, openFilesForSession, checkNumberOfProjects, checkProjectActualFiles, baselineTsserverLogs, protocolFileLocationFromSubstring, verifyGetErrRequest, closeFilesForSession } from "./helpers"; describe("unittests:: tsserver:: Semantic operations on partialSemanticServer", () => { function setup() { - const file1: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/a.ts`, + const file1: File = { + path: `/user/username/projects/myproject/a.ts`, content: `import { y, cc } from "./b"; import { something } from "something"; class c { prop = "hello"; foo() { return this.prop; } }` }; - const file2: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/b.ts`, + const file2: File = { + path: `/user/username/projects/myproject/b.ts`, content: `export { cc } from "./c"; import { something } from "something"; export const y = 10;` }; - const file3: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/c.ts`, + const file3: File = { + path: `/user/username/projects/myproject/c.ts`, content: `export const cc = 10;` }; - const something: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/node_modules/something/index.d.ts`, + const something: File = { + path: `/user/username/projects/myproject/node_modules/something/index.d.ts`, content: "export const something = 10;" }; - const configFile: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/tsconfig.json`, + const configFile: File = { + path: `/user/username/projects/myproject/tsconfig.json`, content: "{}" }; - const host = ts.projectSystem.createServerHost([file1, file2, file3, something, ts.projectSystem.libFile, configFile]); - const session = ts.projectSystem.createSession(host, { + const host = createServerHost([file1, file2, file3, something, libFile, configFile]); + const session = createSession(host, { serverMode: ts.LanguageServiceMode.PartialSemantic, useSingleInferredProject: true, - logger: ts.projectSystem.createLoggerWithInMemoryLogs(host), + logger: createLoggerWithInMemoryLogs(host), }); return { host, session, file1, file2, file3, something, configFile }; } @@ -38,21 +40,21 @@ import { something } from "something"; it("open files are added to inferred project even if config file is present and semantic operations succeed", () => { const { session, file1, file2 } = setup(); const service = session.getProjectService(); - ts.projectSystem.openFilesForSession([file1], session); + openFilesForSession([file1], session); const project = service.inferredProjects[0]; verifyCompletions(); - ts.projectSystem.openFilesForSession([file2], session); - ts.projectSystem.checkNumberOfProjects(service, { inferredProjects: 1 }); - ts.projectSystem.checkProjectActualFiles(project, [ts.projectSystem.libFile.path, file1.path, file2.path]); + openFilesForSession([file2], session); + checkNumberOfProjects(service, { inferredProjects: 1 }); + checkProjectActualFiles(project, [libFile.path, file1.path, file2.path]); verifyCompletions(); - ts.projectSystem.baselineTsserverLogs("partialSemanticServer", "files are added to inferred project", session); + baselineTsserverLogs("partialSemanticServer", "files are added to inferred project", session); function verifyCompletions() { - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Completions, - arguments: ts.projectSystem.protocolFileLocationFromSubstring(file1, "prop", { index: 1 }) + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Completions, + arguments: protocolFileLocationFromSubstring(file1, "prop", { index: 1 }) }); } }); @@ -60,11 +62,11 @@ import { something } from "something"; it("throws on unsupported commands", () => { const { session, file1 } = setup(); const service = session.getProjectService(); - ts.projectSystem.openFilesForSession([file1], session); - const request: ts.projectSystem.protocol.SemanticDiagnosticsSyncRequest = { + openFilesForSession([file1], session); + const request: ts.server.protocol.SemanticDiagnosticsSyncRequest = { type: "request", seq: 1, - command: ts.projectSystem.protocol.CommandTypes.SemanticDiagnosticsSync, + command: ts.server.protocol.CommandTypes.SemanticDiagnosticsSync, arguments: { file: file1.path } }; try { @@ -81,133 +83,133 @@ import { something } from "something"; catch (e) { session.logger.info(e.message); } - ts.projectSystem.baselineTsserverLogs("partialSemanticServer", "throws unsupported commands", session); + baselineTsserverLogs("partialSemanticServer", "throws unsupported commands", session); }); it("allows syntactic diagnostic commands", () => { - const file1: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/a.ts`, + const file1: File = { + path: `/user/username/projects/myproject/a.ts`, content: `if (a < (b + c) { }` }; - const configFile: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/tsconfig.json`, + const configFile: File = { + path: `/user/username/projects/myproject/tsconfig.json`, content: `{}` }; const expectedErrorMessage = "')' expected."; - const host = ts.projectSystem.createServerHost([file1, ts.projectSystem.libFile, configFile]); - const session = ts.projectSystem.createSession(host, { + const host = createServerHost([file1, libFile, configFile]); + const session = createSession(host, { serverMode: ts.LanguageServiceMode.PartialSemantic, useSingleInferredProject: true, - logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) + logger: createLoggerWithInMemoryLogs(host) }); const service = session.getProjectService(); - ts.projectSystem.openFilesForSession([file1], session); - const request: ts.projectSystem.protocol.SyntacticDiagnosticsSyncRequest = { + openFilesForSession([file1], session); + const request: ts.server.protocol.SyntacticDiagnosticsSyncRequest = { type: "request", seq: 1, - command: ts.projectSystem.protocol.CommandTypes.SyntacticDiagnosticsSync, + command: ts.server.protocol.CommandTypes.SyntacticDiagnosticsSync, arguments: { file: file1.path } }; - const response = session.executeCommandSeq(request).response as ts.projectSystem.protocol.SyntacticDiagnosticsSyncResponse["body"]; + const response = session.executeCommandSeq(request).response as ts.server.protocol.SyntacticDiagnosticsSyncResponse["body"]; assert.isDefined(response); assert.equal(response!.length, 1); - assert.equal((response![0] as ts.projectSystem.protocol.Diagnostic).text, expectedErrorMessage); + assert.equal((response![0] as ts.server.protocol.Diagnostic).text, expectedErrorMessage); const project = service.inferredProjects[0]; const diagnostics = project.getLanguageService().getSyntacticDiagnostics(file1.path); assert.isTrue(diagnostics.length === 1); assert.equal(diagnostics[0].messageText, expectedErrorMessage); - ts.projectSystem.verifyGetErrRequest({ session, host, files: [file1], skip: [{ semantic: true, suggestion: true }] }); - ts.projectSystem.baselineTsserverLogs("partialSemanticServer", "syntactic diagnostics are returned with no error", session); + verifyGetErrRequest({ session, host, files: [file1], skip: [{ semantic: true, suggestion: true }] }); + baselineTsserverLogs("partialSemanticServer", "syntactic diagnostics are returned with no error", session); }); it("should not include auto type reference directives", () => { const { host, session, file1 } = setup(); - const atTypes: ts.projectSystem.File = { + const atTypes: File = { path: `/node_modules/@types/somemodule/index.d.ts`, content: "export const something = 10;" }; host.ensureFileOrFolder(atTypes); - ts.projectSystem.openFilesForSession([file1], session); - ts.projectSystem.baselineTsserverLogs("partialSemanticServer", "should not include auto type reference directives", session); + openFilesForSession([file1], session); + baselineTsserverLogs("partialSemanticServer", "should not include auto type reference directives", session); }); it("should not include referenced files from unopened files", () => { - const file1: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/a.ts`, + const file1: File = { + path: `/user/username/projects/myproject/a.ts`, content: `/// -/// +/// function fooA() { }` }; - const file2: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/b.ts`, + const file2: File = { + path: `/user/username/projects/myproject/b.ts`, content: `/// -/// +/// function fooB() { }` }; - const file3: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/c.ts`, + const file3: File = { + path: `/user/username/projects/myproject/c.ts`, content: `function fooC() { }` }; - const something: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/node_modules/something/index.d.ts`, + const something: File = { + path: `/user/username/projects/myproject/node_modules/something/index.d.ts`, content: "function something() {}" }; - const configFile: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/tsconfig.json`, + const configFile: File = { + path: `/user/username/projects/myproject/tsconfig.json`, content: "{}" }; - const host = ts.projectSystem.createServerHost([file1, file2, file3, something, ts.projectSystem.libFile, configFile]); - const session = ts.projectSystem.createSession(host, { + const host = createServerHost([file1, file2, file3, something, libFile, configFile]); + const session = createSession(host, { serverMode: ts.LanguageServiceMode.PartialSemantic, useSingleInferredProject: true, - logger: ts.projectSystem.createLoggerWithInMemoryLogs(host), + logger: createLoggerWithInMemoryLogs(host), }); - ts.projectSystem.openFilesForSession([file1], session); - ts.projectSystem.baselineTsserverLogs("partialSemanticServer", "should not include referenced files from unopened files", session); + openFilesForSession([file1], session); + baselineTsserverLogs("partialSemanticServer", "should not include referenced files from unopened files", session); }); it("should not crash when external module name resolution is reused", () => { const { session, file1, file2, file3 } = setup(); - ts.projectSystem.openFilesForSession([file1], session); + openFilesForSession([file1], session); // Close the file that contains non relative external module name and open some file that doesnt have non relative external module import - ts.projectSystem.closeFilesForSession([file1], session); - ts.projectSystem.openFilesForSession([file3], session); + closeFilesForSession([file1], session); + openFilesForSession([file3], session); // Open file with non relative external module name - ts.projectSystem.openFilesForSession([file2], session); - ts.projectSystem.baselineTsserverLogs("partialSemanticServer", "should not crash when external module name resolution is reused", session); + openFilesForSession([file2], session); + baselineTsserverLogs("partialSemanticServer", "should not crash when external module name resolution is reused", session); }); it("should not create autoImportProvider or handle package jsons", () => { - 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 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: "" }; - const host = ts.projectSystem.createServerHost([angularFormsDts, angularFormsPackageJson, tsconfig, packageJson, indexTs, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { serverMode: ts.LanguageServiceMode.PartialSemantic, useSingleInferredProject: true }); + const host = createServerHost([angularFormsDts, angularFormsPackageJson, tsconfig, packageJson, indexTs, libFile]); + const session = createSession(host, { serverMode: ts.LanguageServiceMode.PartialSemantic, useSingleInferredProject: true }); const service = session.getProjectService(); - ts.projectSystem.openFilesForSession([indexTs], session); + openFilesForSession([indexTs], session); const project = service.inferredProjects[0]; assert.isFalse(project.autoImportProviderHost); assert.isUndefined(project.getPackageJsonAutoImportProvider()); @@ -216,11 +218,11 @@ function fooB() { }` it("should support go-to-definition on module specifiers", () => { const { session, file1 } = setup(); - ts.projectSystem.openFilesForSession([file1], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.DefinitionAndBoundSpan, - arguments: ts.projectSystem.protocolFileLocationFromSubstring(file1, `"./b"`) + openFilesForSession([file1], session); + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.DefinitionAndBoundSpan, + arguments: protocolFileLocationFromSubstring(file1, `"./b"`) }); - ts.projectSystem.baselineTsserverLogs("partialSemanticServer", "should support go-to-definition on module specifiers", session); + baselineTsserverLogs("partialSemanticServer", "should support go-to-definition on module specifiers", session); }); }); diff --git a/src/testRunner/unittests/tsserver/plugins.ts b/src/testRunner/unittests/tsserver/plugins.ts index 2c27ea4687a..de4650ffc64 100644 --- a/src/testRunner/unittests/tsserver/plugins.ts +++ b/src/testRunner/unittests/tsserver/plugins.ts @@ -1,13 +1,15 @@ import * as ts from "../../_namespaces/ts"; import * as Harness from "../../_namespaces/Harness"; +import { createServerHost, File, libFile } from "../virtualFileSystemWithWatch"; +import { createProjectService, createSession, createLoggerWithInMemoryLogs, openFilesForSession, baselineTsserverLogs } from "./helpers"; describe("unittests:: tsserver:: plugins loading", () => { const testProtocolCommand = "testProtocolCommand"; const testProtocolCommandRequest = "testProtocolCommandRequest"; const testProtocolCommandResponse = "testProtocolCommandResponse"; - function createHostWithPlugin(files: readonly ts.projectSystem.File[]) { - const host = ts.projectSystem.createServerHost(files); + function createHostWithPlugin(files: readonly File[]) { + const host = createServerHost(files); const pluginsLoaded: string[] = []; const protocolHandlerRequests: [string, string][] = []; host.require = (_initialPath, moduleName) => { @@ -33,8 +35,8 @@ describe("unittests:: tsserver:: plugins loading", () => { it("With local plugins", () => { const expectedToLoad = ["@myscoped/plugin", "unscopedPlugin"]; const notToLoad = ["../myPlugin", "myPlugin/../malicious"]; - const aTs: ts.projectSystem.File = { path: "/a.ts", content: `class c { prop = "hello"; foo() { return this.prop; } }` }; - const tsconfig: ts.projectSystem.File = { + const aTs: File = { path: "/a.ts", content: `class c { prop = "hello"; foo() { return this.prop; } }` }; + const tsconfig: File = { path: "/tsconfig.json", content: JSON.stringify({ compilerOptions: { @@ -45,8 +47,8 @@ describe("unittests:: tsserver:: plugins loading", () => { } }) }; - const { host, pluginsLoaded } = createHostWithPlugin([aTs, tsconfig, ts.projectSystem.libFile]); - const service = ts.projectSystem.createProjectService(host); + const { host, pluginsLoaded } = createHostWithPlugin([aTs, tsconfig, libFile]); + const service = createProjectService(host); service.openClientFile(aTs.path); assert.deepEqual(pluginsLoaded, expectedToLoad); }); @@ -54,13 +56,13 @@ describe("unittests:: tsserver:: plugins loading", () => { it("With global plugins", () => { const expectedToLoad = ["@myscoped/plugin", "unscopedPlugin"]; const notToLoad = ["../myPlugin", "myPlugin/../malicious"]; - const aTs: ts.projectSystem.File = { path: "/a.ts", content: `class c { prop = "hello"; foo() { return this.prop; } }` }; - const tsconfig: ts.projectSystem.File = { + const aTs: File = { path: "/a.ts", content: `class c { prop = "hello"; foo() { return this.prop; } }` }; + const tsconfig: File = { path: "/tsconfig.json", content: "{}" }; - const { host, pluginsLoaded } = createHostWithPlugin([aTs, tsconfig, ts.projectSystem.libFile]); - const service = ts.projectSystem.createProjectService(host, { globalPlugins: [...expectedToLoad, ...notToLoad] }); + const { host, pluginsLoaded } = createHostWithPlugin([aTs, tsconfig, libFile]); + const service = createProjectService(host, { globalPlugins: [...expectedToLoad, ...notToLoad] }); service.openClientFile(aTs.path); assert.deepEqual(pluginsLoaded, expectedToLoad); }); @@ -68,8 +70,8 @@ describe("unittests:: tsserver:: plugins loading", () => { it("With session and custom protocol message", () => { const pluginName = "some-plugin"; const expectedToLoad = [pluginName]; - const aTs: ts.projectSystem.File = { path: "/a.ts", content: `class c { prop = "hello"; foo() { return this.prop; } }` }; - const tsconfig: ts.projectSystem.File = { + const aTs: File = { path: "/a.ts", content: `class c { prop = "hello"; foo() { return this.prop; } }` }; + const tsconfig: File = { path: "/tsconfig.json", content: JSON.stringify({ compilerOptions: { @@ -80,10 +82,10 @@ describe("unittests:: tsserver:: plugins loading", () => { }) }; - const { host, pluginsLoaded, protocolHandlerRequests } = createHostWithPlugin([aTs, tsconfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host); + const { host, pluginsLoaded, protocolHandlerRequests } = createHostWithPlugin([aTs, tsconfig, libFile]); + const session = createSession(host); - const service = ts.projectSystem.createProjectService(host, { session }); + const service = createProjectService(host, { session }); service.openClientFile(aTs.path); assert.deepEqual(pluginsLoaded, expectedToLoad); @@ -104,9 +106,9 @@ describe("unittests:: tsserver:: plugins loading", () => { }); it("gets external files with config file reload", () => { - const aTs: ts.projectSystem.File = { path: `${ts.tscWatch.projectRoot}/a.ts`, content: `export const x = 10;` }; - const tsconfig: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/tsconfig.json`, + const aTs: File = { path: `/user/username/projects/myproject/a.ts`, content: `export const x = 10;` }; + const tsconfig: File = { + path: `/user/username/projects/myproject/tsconfig.json`, content: JSON.stringify({ compilerOptions: { plugins: [{ name: "some-plugin" }] @@ -119,7 +121,7 @@ describe("unittests:: tsserver:: plugins loading", () => { "some-other-plugin": ["someOtherFile.txt"], }; - const host = ts.projectSystem.createServerHost([aTs, tsconfig, ts.projectSystem.libFile]); + const host = createServerHost([aTs, tsconfig, libFile]); host.require = (_initialPath, moduleName) => { session.logger.logs.push(`Require:: ${moduleName}`); return { @@ -133,8 +135,8 @@ describe("unittests:: tsserver:: plugins loading", () => { error: undefined }; }; - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([aTs], session); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([aTs], session); session.logger.logs.push(`ExternalFiles:: ${JSON.stringify(session.getProjectService().configuredProjects.get(tsconfig.path)!.getExternalFiles())}`); host.writeFile(tsconfig.path, JSON.stringify({ @@ -145,6 +147,6 @@ describe("unittests:: tsserver:: plugins loading", () => { host.runQueuedTimeoutCallbacks(); session.logger.logs.push(`ExternalFiles:: ${JSON.stringify(session.getProjectService().configuredProjects.get(tsconfig.path)!.getExternalFiles())}`); - ts.projectSystem.baselineTsserverLogs("plugins", "gets external files with config file reload", session); + baselineTsserverLogs("plugins", "gets external files with config file reload", session); }); }); \ No newline at end of file diff --git a/src/testRunner/unittests/tsserver/projectErrors.ts b/src/testRunner/unittests/tsserver/projectErrors.ts index 49c06511870..95fd7af6d89 100644 --- a/src/testRunner/unittests/tsserver/projectErrors.ts +++ b/src/testRunner/unittests/tsserver/projectErrors.ts @@ -1,4 +1,6 @@ import * as ts from "../../_namespaces/ts"; +import { createServerHost, File, Folder, libFile } from "../virtualFileSystemWithWatch"; +import { createSession, toExternalFiles, checkNumberOfProjects, openFilesForSession, configuredProjectAt, createProjectService, checkProjectRootFiles, createLoggerWithInMemoryLogs, appendAllScriptInfos, verifyGetErrRequest, baselineTsserverLogs, closeFilesForSession, verifyGetErrScenario, executeSessionRequest } from "./helpers"; describe("unittests:: tsserver:: Project Errors", () => { function checkProjectErrors(projectFiles: ts.server.ProjectFilesWithTSDiagnostics, expectedErrors: readonly string[]): void { @@ -35,8 +37,8 @@ describe("unittests:: tsserver:: Project Errors", () => { path: "/a/b/applib.ts", content: "" }; - 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 projectFileName = "/a/b/test.csproj"; const compilerOptionsRequest: ts.server.protocol.CompilerOptionsDiagnosticsRequest = { @@ -50,10 +52,10 @@ describe("unittests:: tsserver:: Project Errors", () => { projectService.openExternalProject({ projectFileName, options: {}, - rootFiles: ts.projectSystem.toExternalFiles([file1.path, file2.path]) + rootFiles: toExternalFiles([file1.path, file2.path]) }); - ts.projectSystem.checkNumberOfProjects(projectService, { externalProjects: 1 }); + checkNumberOfProjects(projectService, { externalProjects: 1 }); const diags = session.executeCommand(compilerOptionsRequest).response as ts.server.protocol.DiagnosticWithLinePosition[]; // only file1 exists - expect error checkDiagnosticsWithLinePos(diags, ["File '/a/b/applib.ts' not found."]); @@ -61,7 +63,7 @@ describe("unittests:: tsserver:: Project Errors", () => { host.renameFile(file1.path, file2.path); { // only file2 exists - expect error - ts.projectSystem.checkNumberOfProjects(projectService, { externalProjects: 1 }); + checkNumberOfProjects(projectService, { externalProjects: 1 }); const diags = session.executeCommand(compilerOptionsRequest).response as ts.server.protocol.DiagnosticWithLinePosition[]; checkDiagnosticsWithLinePos(diags, ["File '/a/b/app.ts' not found."]); } @@ -69,7 +71,7 @@ describe("unittests:: tsserver:: Project Errors", () => { host.writeFile(file1.path, file1.content); { // both files exist - expect no errors - ts.projectSystem.checkNumberOfProjects(projectService, { externalProjects: 1 }); + checkNumberOfProjects(projectService, { externalProjects: 1 }); const diags = session.executeCommand(compilerOptionsRequest).response as ts.server.protocol.DiagnosticWithLinePosition[]; checkDiagnosticsWithLinePos(diags, []); } @@ -88,12 +90,12 @@ describe("unittests:: tsserver:: Project Errors", () => { path: "/a/b/tsconfig.json", content: JSON.stringify({ files: [file1, file2].map(f => ts.getBaseFileName(f.path)) }) }; - const host = ts.projectSystem.createServerHost([file1, config, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host); + const host = createServerHost([file1, config, libFile]); + const session = createSession(host); const projectService = session.getProjectService(); - ts.projectSystem.openFilesForSession([file1], session); - ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 }); - const project = ts.projectSystem.configuredProjectAt(projectService, 0); + openFilesForSession([file1], session); + checkNumberOfProjects(projectService, { configuredProjects: 1 }); + const project = configuredProjectAt(projectService, 0); const compilerOptionsRequest: ts.server.protocol.CompilerOptionsDiagnosticsRequest = { type: "request", command: ts.server.CommandNames.CompilerOptionsDiagnosticsFull, @@ -105,7 +107,7 @@ describe("unittests:: tsserver:: Project Errors", () => { host.writeFile(file2.path, file2.content); - ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 }); + checkNumberOfProjects(projectService, { configuredProjects: 1 }); diags = session.executeCommand(compilerOptionsRequest).response as ts.server.protocol.DiagnosticWithLinePosition[]; checkDiagnosticsWithLinePos(diags, []); }); @@ -127,8 +129,8 @@ describe("unittests:: tsserver:: Project Errors", () => { path: correctConfig.path, content: correctConfig.content.substr(1) }; - const host = ts.projectSystem.createServerHost([file1, file2, corruptedConfig]); - const projectService = ts.projectSystem.createProjectService(host); + const host = createServerHost([file1, file2, corruptedConfig]); + const projectService = createProjectService(host); projectService.openClientFile(file1.path); { @@ -136,7 +138,7 @@ describe("unittests:: tsserver:: Project Errors", () => { const configuredProject = ts.find(projectService.synchronizeProjectList([]), f => f.info!.projectName === corruptedConfig.path)!; assert.isTrue(configuredProject !== undefined, "should find configured project"); checkProjectErrors(configuredProject, []); - const projectErrors = ts.projectSystem.configuredProjectAt(projectService, 0).getAllProjectErrors(); + const projectErrors = configuredProjectAt(projectService, 0).getAllProjectErrors(); checkProjectErrorsWorker(projectErrors, [ "'{' expected." ]); @@ -150,7 +152,7 @@ describe("unittests:: tsserver:: Project Errors", () => { const configuredProject = ts.find(projectService.synchronizeProjectList([]), f => f.info!.projectName === corruptedConfig.path)!; assert.isTrue(configuredProject !== undefined, "should find configured project"); checkProjectErrors(configuredProject, []); - const projectErrors = ts.projectSystem.configuredProjectAt(projectService, 0).getAllProjectErrors(); + const projectErrors = configuredProjectAt(projectService, 0).getAllProjectErrors(); checkProjectErrorsWorker(projectErrors, []); } }); @@ -172,8 +174,8 @@ describe("unittests:: tsserver:: Project Errors", () => { path: correctConfig.path, content: correctConfig.content.substr(1) }; - const host = ts.projectSystem.createServerHost([file1, file2, correctConfig]); - const projectService = ts.projectSystem.createProjectService(host); + const host = createServerHost([file1, file2, correctConfig]); + const projectService = createProjectService(host); projectService.openClientFile(file1.path); { @@ -181,7 +183,7 @@ describe("unittests:: tsserver:: Project Errors", () => { const configuredProject = ts.find(projectService.synchronizeProjectList([]), f => f.info!.projectName === corruptedConfig.path)!; assert.isTrue(configuredProject !== undefined, "should find configured project"); checkProjectErrors(configuredProject, []); - const projectErrors = ts.projectSystem.configuredProjectAt(projectService, 0).getAllProjectErrors(); + const projectErrors = configuredProjectAt(projectService, 0).getAllProjectErrors(); checkProjectErrorsWorker(projectErrors, []); } // break config and trigger watcher @@ -191,7 +193,7 @@ describe("unittests:: tsserver:: Project Errors", () => { const configuredProject = ts.find(projectService.synchronizeProjectList([]), f => f.info!.projectName === corruptedConfig.path)!; assert.isTrue(configuredProject !== undefined, "should find configured project"); checkProjectErrors(configuredProject, []); - const projectErrors = ts.projectSystem.configuredProjectAt(projectService, 0).getAllProjectErrors(); + const projectErrors = configuredProjectAt(projectService, 0).getAllProjectErrors(); checkProjectErrorsWorker(projectErrors, [ "'{' expected." ]); @@ -211,36 +213,36 @@ describe("unittests:: tsserver:: Project Errors are reported as appropriate", () path: "/a/b/tsconfig.json", content: "{" }; - const host = ts.projectSystem.createServerHost([file1, corruptedConfig]); - const projectService = ts.projectSystem.createProjectService(host); + const host = createServerHost([file1, corruptedConfig]); + const projectService = createProjectService(host); projectService.openClientFile(file1.path); projectService.checkNumberOfProjects({ configuredProjects: 1 }); const project = projectService.findProject(corruptedConfig.path)!; - ts.projectSystem.checkProjectRootFiles(project, [file1.path]); + checkProjectRootFiles(project, [file1.path]); }); describe("when opening new file that doesnt exist on disk yet", () => { function verifyNonExistentFile(useProjectRoot: boolean) { const folderPath = "/user/someuser/projects/someFolder"; - const fileInRoot: ts.projectSystem.File = { + const fileInRoot: File = { path: `/src/somefile.d.ts`, content: "class c { }" }; - const fileInProjectRoot: ts.projectSystem.File = { + const fileInProjectRoot: File = { path: `${folderPath}/src/somefile.d.ts`, content: "class c { }" }; - const host = ts.projectSystem.createServerHost([ts.projectSystem.libFile, fileInRoot, fileInProjectRoot]); - const session = ts.projectSystem.createSession(host, { canUseEvents: true, logger: ts.projectSystem.createLoggerWithInMemoryLogs(host), useInferredProjectPerProjectRoot: true }); + const host = createServerHost([libFile, fileInRoot, fileInProjectRoot]); + const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host), useInferredProjectPerProjectRoot: true }); const untitledFile = "untitled:Untitled-1"; const refPathNotFound1 = "../../../../../../typings/@epic/Core.d.ts"; const refPathNotFound2 = "./src/somefile.d.ts"; const fileContent = `/// /// `; - session.executeCommandSeq({ + session.executeCommandSeq({ command: ts.server.CommandNames.Open, arguments: { file: untitledFile, @@ -249,12 +251,12 @@ describe("unittests:: tsserver:: Project Errors are reported as appropriate", () projectRootPath: useProjectRoot ? folderPath : undefined } }); - ts.projectSystem.appendAllScriptInfos(session.getProjectService(), session.logger.logs); + appendAllScriptInfos(session.getProjectService(), session.logger.logs); // Since this is not js project so no typings are queued host.checkTimeoutQueueLength(0); - ts.projectSystem.verifyGetErrRequest({ session, host, files: [untitledFile] }); - ts.projectSystem.baselineTsserverLogs("projectErrors", `when opening new file that doesnt exist on disk yet ${useProjectRoot ? "with projectRoot" : "without projectRoot"}`, session); + verifyGetErrRequest({ session, host, files: [untitledFile] }); + baselineTsserverLogs("projectErrors", `when opening new file that doesnt exist on disk yet ${useProjectRoot ? "with projectRoot" : "without projectRoot"}`, session); } it("has projectRoot", () => { @@ -268,42 +270,42 @@ describe("unittests:: tsserver:: Project Errors are reported as appropriate", () it("folder rename updates project structure and reports no errors", () => { const projectDir = "/a/b/projects/myproject"; - const app: ts.projectSystem.File = { + const app: File = { path: `${projectDir}/bar/app.ts`, content: "class Bar implements foo.Foo { getFoo() { return ''; } get2() { return 1; } }" }; - const foo: ts.projectSystem.File = { + const foo: File = { path: `${projectDir}/foo/foo.ts`, content: "declare namespace foo { interface Foo { get2(): number; getFoo(): string; } }" }; - const configFile: ts.projectSystem.File = { + const configFile: File = { path: `${projectDir}/tsconfig.json`, content: JSON.stringify({ compilerOptions: { module: "none", targer: "es5" }, exclude: ["node_modules"] }) }; - const host = ts.projectSystem.createServerHost([app, foo, configFile]); - const session = ts.projectSystem.createSession(host, { canUseEvents: true, logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); + const host = createServerHost([app, foo, configFile]); + const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); - session.executeCommandSeq({ + session.executeCommandSeq({ command: ts.server.CommandNames.Open, arguments: { file: app.path, } }); - ts.projectSystem.verifyGetErrRequest({ session, host, files: [app] }); + verifyGetErrRequest({ session, host, files: [app] }); host.renameFolder(`${projectDir}/foo`, `${projectDir}/foo2`); host.runQueuedTimeoutCallbacks(); host.runQueuedTimeoutCallbacks(); - ts.projectSystem.verifyGetErrRequest({ session, host, files: [app] }); - ts.projectSystem.baselineTsserverLogs("projectErrors", `folder rename updates project structure and reports no errors`, session); + verifyGetErrRequest({ session, host, files: [app] }); + baselineTsserverLogs("projectErrors", `folder rename updates project structure and reports no errors`, session); }); it("Getting errors before opening file", () => { - const file: ts.projectSystem.File = { + const file: File = { path: "/a/b/project/file.ts", content: "let x: number = false;" }; - const host = ts.projectSystem.createServerHost([file, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { canUseEvents: true, logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - session.executeCommandSeq({ + const host = createServerHost([file, libFile]); + const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); + session.executeCommandSeq({ command: ts.server.CommandNames.Geterr, arguments: { delay: 0, @@ -312,69 +314,69 @@ describe("unittests:: tsserver:: Project Errors are reported as appropriate", () }); host.checkTimeoutQueueLengthAndRun(1); - ts.projectSystem.baselineTsserverLogs("projectErrors", "getting errors before opening file", session); + baselineTsserverLogs("projectErrors", "getting errors before opening file", session); }); it("Reports errors correctly when file referenced by inferred project root, is opened right after closing the root file", () => { - const app: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/src/client/app.js`, + const app: File = { + path: `/user/username/projects/myproject/src/client/app.js`, content: "" }; - const serverUtilities: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/src/server/utilities.js`, + const serverUtilities: File = { + path: `/user/username/projects/myproject/src/server/utilities.js`, content: `function getHostName() { return "hello"; } export { getHostName };` }; - const backendTest: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/test/backend/index.js`, + const backendTest: File = { + path: `/user/username/projects/myproject/test/backend/index.js`, content: `import { getHostName } from '../../src/server/utilities';export default getHostName;` }; - const files = [ts.projectSystem.libFile, app, serverUtilities, backendTest]; - const host = ts.projectSystem.createServerHost(files); - const session = ts.projectSystem.createSession(host, { useInferredProjectPerProjectRoot: true, canUseEvents: true, logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([{ file: app, projectRootPath: ts.tscWatch.projectRoot }], session); - ts.projectSystem.openFilesForSession([{ file: backendTest, projectRootPath: ts.tscWatch.projectRoot }], session); - ts.projectSystem.verifyGetErrRequest({ session, host, files: [backendTest.path, app.path] }); - ts.projectSystem.closeFilesForSession([backendTest], session); - ts.projectSystem.openFilesForSession([{ file: serverUtilities.path, projectRootPath: ts.tscWatch.projectRoot }], session); - ts.projectSystem.verifyGetErrRequest({ session, host, files: [serverUtilities.path, app.path] }); - ts.projectSystem.baselineTsserverLogs("projectErrors", `reports errors correctly when file referenced by inferred project root, is opened right after closing the root file`, session); + const files = [libFile, app, serverUtilities, backendTest]; + const host = createServerHost(files); + const session = createSession(host, { useInferredProjectPerProjectRoot: true, canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([{ file: app, projectRootPath: "/user/username/projects/myproject" }], session); + openFilesForSession([{ file: backendTest, projectRootPath: "/user/username/projects/myproject" }], session); + verifyGetErrRequest({ session, host, files: [backendTest.path, app.path] }); + closeFilesForSession([backendTest], session); + openFilesForSession([{ file: serverUtilities.path, projectRootPath: "/user/username/projects/myproject" }], session); + verifyGetErrRequest({ session, host, files: [serverUtilities.path, app.path] }); + baselineTsserverLogs("projectErrors", `reports errors correctly when file referenced by inferred project root, is opened right after closing the root file`, session); }); it("Correct errors when resolution resolves to file that has same ambient module and is also module", () => { const projectRootPath = "/users/username/projects/myproject"; - const aFile: ts.projectSystem.File = { + const aFile: File = { path: `${projectRootPath}/src/a.ts`, content: `import * as myModule from "@custom/plugin"; function foo() { // hello }` }; - const config: ts.projectSystem.File = { + const config: File = { path: `${projectRootPath}/tsconfig.json`, content: JSON.stringify({ include: ["src"] }) }; - const plugin: ts.projectSystem.File = { + const plugin: File = { path: `${projectRootPath}/node_modules/@custom/plugin/index.d.ts`, content: `import './proposed'; declare module '@custom/plugin' { export const version: string; }` }; - const pluginProposed: ts.projectSystem.File = { + const pluginProposed: File = { path: `${projectRootPath}/node_modules/@custom/plugin/proposed.d.ts`, content: `declare module '@custom/plugin' { export const bar = 10; }` }; - const files = [ts.projectSystem.libFile, aFile, config, plugin, pluginProposed]; - const host = ts.projectSystem.createServerHost(files); - const session = ts.projectSystem.createSession(host, { canUseEvents: true, logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([aFile], session); + const files = [libFile, aFile, config, plugin, pluginProposed]; + const host = createServerHost(files); + const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([aFile], session); checkErrors(); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: aFile.path, line: 3, @@ -385,28 +387,28 @@ declare module '@custom/plugin' { } }); checkErrors(); - ts.projectSystem.baselineTsserverLogs("projectErrors", `correct errors when resolution resolves to file that has same ambient module and is also module`, session); + baselineTsserverLogs("projectErrors", `correct errors when resolution resolves to file that has same ambient module and is also module`, session); function checkErrors() { host.checkTimeoutQueueLength(0); - ts.projectSystem.verifyGetErrRequest({ session, host, files: [aFile] }); + verifyGetErrRequest({ session, host, files: [aFile] }); } }); describe("when semantic error returns includes global error", () => { - const file: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/ui.ts`, + const file: File = { + path: `/user/username/projects/myproject/ui.ts`, content: `const x = async (_action: string) => { };` }; - const config: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/tsconfig.json`, + const config: File = { + path: `/user/username/projects/myproject/tsconfig.json`, content: "{}" }; - ts.projectSystem.verifyGetErrScenario({ + verifyGetErrScenario({ scenario: "projectErrors", subScenario: "when semantic error returns includes global error", - allFiles: () => [ts.projectSystem.libFile, file, config], + allFiles: () => [libFile, file, config], openFiles: () => [file], getErrRequest: () => [file], getErrForProjectRequest: () => [{ project: file, files: [file] }], @@ -417,11 +419,11 @@ declare module '@custom/plugin' { describe("unittests:: tsserver:: Project Errors for Configure file diagnostics events", () => { it("are generated when the config file has errors", () => { - const file: ts.projectSystem.File = { + const file: File = { path: "/a/b/app.ts", content: "let x = 10" }; - const configFile: ts.projectSystem.File = { + const configFile: File = { path: "/a/b/tsconfig.json", content: `{ "compilerOptions": { @@ -430,31 +432,31 @@ describe("unittests:: tsserver:: Project Errors for Configure file diagnostics e } }` }; - const host = ts.projectSystem.createServerHost([file, ts.projectSystem.libFile, configFile]); - const session = ts.projectSystem.createSession(host, { canUseEvents: true, logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([file], session); - ts.projectSystem.baselineTsserverLogs("projectErrors", "configFileDiagnostic events are generated when the config file has errors", session); + const host = createServerHost([file, libFile, configFile]); + const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([file], session); + baselineTsserverLogs("projectErrors", "configFileDiagnostic events are generated when the config file has errors", session); }); it("are generated when the config file doesn't have errors", () => { - const file: ts.projectSystem.File = { + const file: File = { path: "/a/b/app.ts", content: "let x = 10" }; - const configFile: ts.projectSystem.File = { + const configFile: File = { path: "/a/b/tsconfig.json", content: `{ "compilerOptions": {} }` }; - const host = ts.projectSystem.createServerHost([file, ts.projectSystem.libFile, configFile]); - const session = ts.projectSystem.createSession(host, { canUseEvents: true, logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([file], session); - ts.projectSystem.baselineTsserverLogs("projectErrors", "configFileDiagnostic events are generated when the config file doesnt have errors", session); + const host = createServerHost([file, libFile, configFile]); + const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([file], session); + baselineTsserverLogs("projectErrors", "configFileDiagnostic events are generated when the config file doesnt have errors", session); }); it("are generated when the config file changes", () => { - const file: ts.projectSystem.File = { + const file: File = { path: "/a/b/app.ts", content: "let x = 10" }; @@ -465,9 +467,9 @@ describe("unittests:: tsserver:: Project Errors for Configure file diagnostics e }` }; - const host = ts.projectSystem.createServerHost([file, ts.projectSystem.libFile, configFile]); - const session = ts.projectSystem.createSession(host, { canUseEvents: true, logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([file], session); + const host = createServerHost([file, libFile, configFile]); + const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([file], session); configFile.content = `{ "compilerOptions": { @@ -482,23 +484,23 @@ describe("unittests:: tsserver:: Project Errors for Configure file diagnostics e }`; host.writeFile(configFile.path, configFile.content); host.runQueuedTimeoutCallbacks(); - ts.projectSystem.baselineTsserverLogs("projectErrors", "configFileDiagnostic events are generated when the config file changes", session); + baselineTsserverLogs("projectErrors", "configFileDiagnostic events are generated when the config file changes", session); }); it("are not generated when the config file does not include file opened and config file has errors", () => { - const file: ts.projectSystem.File = { + const file: File = { path: "/a/b/app.ts", content: "let x = 10" }; - const file2: ts.projectSystem.File = { + const file2: File = { path: "/a/b/test.ts", content: "let x = 10" }; - const file3: ts.projectSystem.File = { + const file3: File = { path: "/a/b/test2.ts", content: "let xy = 10" }; - const configFile: ts.projectSystem.File = { + const configFile: File = { path: "/a/b/tsconfig.json", content: `{ "compilerOptions": { @@ -508,21 +510,21 @@ describe("unittests:: tsserver:: Project Errors for Configure file diagnostics e "files": ["app.ts"] }` }; - const host = ts.projectSystem.createServerHost([file, ts.projectSystem.libFile, configFile]); - const session = ts.projectSystem.createSession(host, { canUseEvents: true, logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([file2], session); - ts.projectSystem.openFilesForSession([file], session); + const host = createServerHost([file, libFile, configFile]); + const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([file2], session); + openFilesForSession([file], session); // We generate only if project is created when opening file from the project - ts.projectSystem.openFilesForSession([file3], session); - ts.projectSystem.baselineTsserverLogs("projectErrors", "configFileDiagnostic events are not generated when the config file does not include file opened and config file has errors", session); + openFilesForSession([file3], session); + baselineTsserverLogs("projectErrors", "configFileDiagnostic events are not generated when the config file does not include file opened and config file has errors", session); }); it("are not generated when the config file has errors but suppressDiagnosticEvents is true", () => { - const file: ts.projectSystem.File = { + const file: File = { path: "/a/b/app.ts", content: "let x = 10" }; - const configFile: ts.projectSystem.File = { + const configFile: File = { path: "/a/b/tsconfig.json", content: `{ "compilerOptions": { @@ -531,48 +533,48 @@ describe("unittests:: tsserver:: Project Errors for Configure file diagnostics e } }` }; - const host = ts.projectSystem.createServerHost([file, ts.projectSystem.libFile, configFile]); - const session = ts.projectSystem.createSession(host, { canUseEvents: true, suppressDiagnosticEvents: true, logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([file], session); - ts.projectSystem.baselineTsserverLogs("projectErrors", "configFileDiagnostic events are not generated when the config file has errors but suppressDiagnosticEvents is true", session); + const host = createServerHost([file, libFile, configFile]); + const session = createSession(host, { canUseEvents: true, suppressDiagnosticEvents: true, logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([file], session); + baselineTsserverLogs("projectErrors", "configFileDiagnostic events are not generated when the config file has errors but suppressDiagnosticEvents is true", session); }); it("are not generated when the config file does not include file opened and doesnt contain any errors", () => { - const file: ts.projectSystem.File = { + const file: File = { path: "/a/b/app.ts", content: "let x = 10" }; - const file2: ts.projectSystem.File = { + const file2: File = { path: "/a/b/test.ts", content: "let x = 10" }; - const file3: ts.projectSystem.File = { + const file3: File = { path: "/a/b/test2.ts", content: "let xy = 10" }; - const configFile: ts.projectSystem.File = { + const configFile: File = { path: "/a/b/tsconfig.json", content: `{ "files": ["app.ts"] }` }; - const host = ts.projectSystem.createServerHost([file, file2, file3, ts.projectSystem.libFile, configFile]); - const session = ts.projectSystem.createSession(host, { canUseEvents: true, logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([file2], session); - ts.projectSystem.openFilesForSession([file], session); + const host = createServerHost([file, file2, file3, libFile, configFile]); + const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([file2], session); + openFilesForSession([file], session); // We generate only if project is created when opening file from the project - ts.projectSystem.openFilesForSession([file3], session); - ts.projectSystem.baselineTsserverLogs("projectErrors", "configFileDiagnostic events are not generated when the config file does not include file opened and doesnt contain any errors", session); + openFilesForSession([file3], session); + baselineTsserverLogs("projectErrors", "configFileDiagnostic events are not generated when the config file does not include file opened and doesnt contain any errors", session); }); it("contains the project reference errors", () => { - const file: ts.projectSystem.File = { + const file: File = { path: "/a/b/app.ts", content: "let x = 10" }; const noSuchTsconfig = "no-such-tsconfig.json"; - const configFile: ts.projectSystem.File = { + const configFile: File = { path: "/a/b/tsconfig.json", content: `{ "files": ["app.ts"], @@ -580,10 +582,10 @@ describe("unittests:: tsserver:: Project Errors for Configure file diagnostics e }` }; - const host = ts.projectSystem.createServerHost([file, ts.projectSystem.libFile, configFile]); - const session = ts.projectSystem.createSession(host, { canUseEvents: true, logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([file], session); - ts.projectSystem.baselineTsserverLogs("projectErrors", "configFileDiagnostic events contains the project reference errors", session); + const host = createServerHost([file, libFile, configFile]); + const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([file], session); + baselineTsserverLogs("projectErrors", "configFileDiagnostic events contains the project reference errors", session); }); }); @@ -593,12 +595,12 @@ describe("unittests:: tsserver:: Project Errors dont include overwrite emit erro path: "/a/b/f1.js", content: "function test1() { }" }; - const host = ts.projectSystem.createServerHost([f1, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host); - ts.projectSystem.openFilesForSession([f1], session); + const host = createServerHost([f1, libFile]); + const session = createSession(host); + openFilesForSession([f1], session); const projectService = session.getProjectService(); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 1 }); + checkNumberOfProjects(projectService, { inferredProjects: 1 }); const projectName = projectService.inferredProjects[0].getProjectName(); const diags = session.executeCommand({ @@ -606,7 +608,7 @@ describe("unittests:: tsserver:: Project Errors dont include overwrite emit erro command: ts.server.CommandNames.CompilerOptionsDiagnosticsFull, seq: 2, arguments: { projectFileName: projectName } - } as ts.server.protocol.CompilerOptionsDiagnosticsRequest).response as readonly ts.projectSystem.protocol.DiagnosticWithLinePosition[]; + } as ts.server.protocol.CompilerOptionsDiagnosticsRequest).response as readonly ts.server.protocol.DiagnosticWithLinePosition[]; assert.isTrue(diags.length === 0); session.executeCommand({ @@ -620,7 +622,7 @@ describe("unittests:: tsserver:: Project Errors dont include overwrite emit erro command: ts.server.CommandNames.CompilerOptionsDiagnosticsFull, seq: 4, arguments: { projectFileName: projectName } - } as ts.server.protocol.CompilerOptionsDiagnosticsRequest).response as readonly ts.projectSystem.protocol.DiagnosticWithLinePosition[]; + } as ts.server.protocol.CompilerOptionsDiagnosticsRequest).response as readonly ts.server.protocol.DiagnosticWithLinePosition[]; assert.isTrue(diagsAfterUpdate.length === 0); }); @@ -629,18 +631,18 @@ describe("unittests:: tsserver:: Project Errors dont include overwrite emit erro path: "/a/b/f1.js", content: "function test1() { }" }; - const host = ts.projectSystem.createServerHost([f1, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host); + const host = createServerHost([f1, libFile]); + const session = createSession(host); const projectService = session.getProjectService(); const projectFileName = "/a/b/project.csproj"; - const externalFiles = ts.projectSystem.toExternalFiles([f1.path]); + const externalFiles = toExternalFiles([f1.path]); projectService.openExternalProject({ projectFileName, rootFiles: externalFiles, options: {} - } as ts.projectSystem.protocol.ExternalProject); + } as ts.server.protocol.ExternalProject); - ts.projectSystem.checkNumberOfProjects(projectService, { externalProjects: 1 }); + checkNumberOfProjects(projectService, { externalProjects: 1 }); const diags = session.executeCommand({ type: "request", @@ -692,13 +694,13 @@ describe("unittests:: tsserver:: Project Errors reports Options Diagnostic locat path: "/a/b/tsconfig.json", content: configFileContentWithComment }; - const host = ts.projectSystem.createServerHost([file, ts.projectSystem.libFile, configFile]); - const session = ts.projectSystem.createSession(host); - ts.projectSystem.openFilesForSession([file], session); + const host = createServerHost([file, libFile, configFile]); + const session = createSession(host); + openFilesForSession([file], session); const projectService = session.getProjectService(); - ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 }); - const projectName = ts.projectSystem.configuredProjectAt(projectService, 0).getProjectName(); + checkNumberOfProjects(projectService, { configuredProjects: 1 }); + const projectName = configuredProjectAt(projectService, 0).getProjectName(); const diags = session.executeCommand({ type: "request", @@ -737,19 +739,19 @@ describe("unittests:: tsserver:: Project Errors reports Options Diagnostic locat describe("unittests:: tsserver:: Project Errors with config file change", () => { it("Updates diagnostics when '--noUnusedLabels' changes", () => { - const aTs: ts.projectSystem.File = { path: "/a.ts", content: "label: while (1) {}" }; + const aTs: File = { path: "/a.ts", content: "label: while (1) {}" }; const options = (allowUnusedLabels: boolean) => `{ "compilerOptions": { "allowUnusedLabels": ${allowUnusedLabels} } }`; - const tsconfig: ts.projectSystem.File = { path: "/tsconfig.json", content: options(/*allowUnusedLabels*/ true) }; + const tsconfig: File = { path: "/tsconfig.json", content: options(/*allowUnusedLabels*/ true) }; - const host = ts.projectSystem.createServerHost([aTs, tsconfig]); - const session = ts.projectSystem.createSession(host); - ts.projectSystem.openFilesForSession([aTs], session); + const host = createServerHost([aTs, tsconfig]); + const session = createSession(host); + openFilesForSession([aTs], session); host.modifyFile(tsconfig.path, options(/*allowUnusedLabels*/ false)); host.runQueuedTimeoutCallbacks(); - const response = ts.projectSystem.executeSessionRequest(session, ts.projectSystem.protocol.CommandTypes.SemanticDiagnosticsSync, { file: aTs.path }) as ts.projectSystem.protocol.Diagnostic[] | undefined; - assert.deepEqual(response, [ + const response = executeSessionRequest(session, ts.server.protocol.CommandTypes.SemanticDiagnosticsSync, { file: aTs.path }) as ts.server.protocol.Diagnostic[] | undefined; + assert.deepEqual(response, [ { start: { line: 1, offset: 1 }, end: { line: 1, offset: 1 + "label".length }, @@ -767,18 +769,18 @@ describe("unittests:: tsserver:: Project Errors with config file change", () => describe("unittests:: tsserver:: Project Errors with resolveJsonModule", () => { function createSessionForTest({ include }: { include: readonly string[]; }) { - const test: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/src/test.ts`, + const test: File = { + path: `/user/username/projects/myproject/src/test.ts`, content: `import * as blabla from "./blabla.json"; declare var console: any; console.log(blabla);` }; - const blabla: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/src/blabla.json`, + const blabla: File = { + path: `/user/username/projects/myproject/src/blabla.json`, content: "{}" }; - 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: { resolveJsonModule: true, @@ -788,9 +790,9 @@ console.log(blabla);` }) }; - const host = ts.projectSystem.createServerHost([test, blabla, ts.projectSystem.libFile, tsconfig]); - const session = ts.projectSystem.createSession(host, { canUseEvents: true, logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([test], session); + const host = createServerHost([test, blabla, libFile, tsconfig]); + const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([test], session); return { host, session, test, blabla, tsconfig }; } @@ -798,56 +800,56 @@ console.log(blabla);` const { host, session, test } = createSessionForTest({ include: ["./src/*.ts", "./src/*.json"] }); - ts.projectSystem.verifyGetErrRequest({ session, host, files: [test] }); - ts.projectSystem.baselineTsserverLogs("projectErrors", `should not report incorrect error when json is root file found by tsconfig`, session); + verifyGetErrRequest({ session, host, files: [test] }); + baselineTsserverLogs("projectErrors", `should not report incorrect error when json is root file found by tsconfig`, session); }); it("should report error when json is not root file found by tsconfig", () => { const { host, session, test } = createSessionForTest({ include: ["./src/*.ts"] }); - ts.projectSystem.verifyGetErrRequest({ session, host, files: [test] }); - ts.projectSystem.baselineTsserverLogs("projectErrors", `should report error when json is not root file found by tsconfig`, session); + verifyGetErrRequest({ session, host, files: [test] }); + baselineTsserverLogs("projectErrors", `should report error when json is not root file found by tsconfig`, session); }); }); describe("unittests:: tsserver:: Project Errors with npm install when", () => { function verifyNpmInstall(timeoutDuringPartialInstallation: boolean) { - const main: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/src/main.ts`, + const main: File = { + path: `/user/username/projects/myproject/src/main.ts`, content: "import * as _a from '@angular/core';" }; - const config: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/tsconfig.json`, + const config: File = { + path: `/user/username/projects/myproject/tsconfig.json`, content: "{}" }; // Move things from staging to node_modules without triggering watch - const moduleFile: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/node_modules/@angular/core/index.d.ts`, + const moduleFile: File = { + path: `/user/username/projects/myproject/node_modules/@angular/core/index.d.ts`, content: `export const y = 10;` }; - const projectFiles = [main, ts.projectSystem.libFile, config]; - const host = ts.projectSystem.createServerHost(projectFiles); - const session = ts.projectSystem.createSession(host, { canUseEvents: true, logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([{ file: main, projectRootPath: ts.tscWatch.projectRoot }], session); - ts.projectSystem.verifyGetErrRequest({ session, host, files: [main] }); + const projectFiles = [main, libFile, config]; + const host = createServerHost(projectFiles); + const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([{ file: main, projectRootPath: "/user/username/projects/myproject" }], session); + verifyGetErrRequest({ session, host, files: [main] }); let npmInstallComplete = false; // Simulate npm install - let filesAndFoldersToAdd: (ts.projectSystem.File | ts.projectSystem.Folder)[] = [ - { path: `${ts.tscWatch.projectRoot}/node_modules` }, // This should queue update - { path: `${ts.tscWatch.projectRoot}/node_modules/.staging` }, - { path: `${ts.tscWatch.projectRoot}/node_modules/.staging/@babel` }, - { path: `${ts.tscWatch.projectRoot}/node_modules/.staging/@babel/helper-plugin-utils-a06c629f` }, - { path: `${ts.tscWatch.projectRoot}/node_modules/.staging/core-js-db53158d` }, + let filesAndFoldersToAdd: (File | Folder)[] = [ + { path: `/user/username/projects/myproject/node_modules` }, // This should queue update + { path: `/user/username/projects/myproject/node_modules/.staging` }, + { path: `/user/username/projects/myproject/node_modules/.staging/@babel` }, + { path: `/user/username/projects/myproject/node_modules/.staging/@babel/helper-plugin-utils-a06c629f` }, + { path: `/user/username/projects/myproject/node_modules/.staging/core-js-db53158d` }, ]; verifyWhileNpmInstall(3); filesAndFoldersToAdd = [ - { path: `${ts.tscWatch.projectRoot}/node_modules/.staging/@angular/platform-browser-dynamic-5efaaa1a` }, - { path: `${ts.tscWatch.projectRoot}/node_modules/.staging/@angular/cli-c1e44b05/models/analytics.d.ts`, content: `export const x = 10;` }, - { path: `${ts.tscWatch.projectRoot}/node_modules/.staging/@angular/core-0963aebf/index.d.ts`, content: `export const y = 10;` }, + { path: `/user/username/projects/myproject/node_modules/.staging/@angular/platform-browser-dynamic-5efaaa1a` }, + { path: `/user/username/projects/myproject/node_modules/.staging/@angular/cli-c1e44b05/models/analytics.d.ts`, content: `export const x = 10;` }, + { path: `/user/username/projects/myproject/node_modules/.staging/@angular/core-0963aebf/index.d.ts`, content: `export const y = 10;` }, ]; // Since we added/removed in .staging no timeout verifyWhileNpmInstall(0); @@ -858,13 +860,13 @@ describe("unittests:: tsserver:: Project Errors with npm install when", () => { verifyWhileNpmInstall(0); // Remove staging folder to remove errors - host.deleteFolder(`${ts.tscWatch.projectRoot}/node_modules/.staging`, /*recursive*/ true); + host.deleteFolder(`/user/username/projects/myproject/node_modules/.staging`, /*recursive*/ true); npmInstallComplete = true; projectFiles.push(moduleFile); // Additional watch for watching script infos from node_modules verifyWhileNpmInstall(3); - ts.projectSystem.baselineTsserverLogs("projectErrors", `npm install when timeout occurs ${timeoutDuringPartialInstallation ? "inbetween" : "after"} installation`, session); + baselineTsserverLogs("projectErrors", `npm install when timeout occurs ${timeoutDuringPartialInstallation ? "inbetween" : "after"} installation`, session); function verifyWhileNpmInstall(timeouts: number) { filesAndFoldersToAdd.forEach(f => host.ensureFileOrFolder(f)); @@ -877,7 +879,7 @@ describe("unittests:: tsserver:: Project Errors with npm install when", () => { else { host.checkTimeoutQueueLength(timeouts ? 3 : 2); } - ts.projectSystem.verifyGetErrRequest({ session, host, files: [main], existingTimeouts: !npmInstallComplete && !timeoutDuringPartialInstallation ? timeouts ? 3 : 2 : undefined }); + verifyGetErrRequest({ session, host, files: [main], existingTimeouts: !npmInstallComplete && !timeoutDuringPartialInstallation ? timeouts ? 3 : 2 : undefined }); } } diff --git a/src/testRunner/unittests/tsserver/projectReferenceCompileOnSave.ts b/src/testRunner/unittests/tsserver/projectReferenceCompileOnSave.ts index f2a6941347b..1daceed20d9 100644 --- a/src/testRunner/unittests/tsserver/projectReferenceCompileOnSave.ts +++ b/src/testRunner/unittests/tsserver/projectReferenceCompileOnSave.ts @@ -1,22 +1,25 @@ import * as ts from "../../_namespaces/ts"; +import { createServerHost, File, libFile } from "../virtualFileSystemWithWatch"; +import { ensureErrorFreeBuild } from "../tscWatch/helpers"; +import { createSession, createLoggerWithInMemoryLogs, openFilesForSession, baselineTsserverLogs, protocolToLocation } from "./helpers"; describe("unittests:: tsserver:: with project references and compile on save", () => { - const dependecyLocation = `${ts.tscWatch.projectRoot}/dependency`; - const usageLocation = `${ts.tscWatch.projectRoot}/usage`; - const dependencyTs: ts.projectSystem.File = { + const dependecyLocation = `/user/username/projects/myproject/dependency`; + const usageLocation = `/user/username/projects/myproject/usage`; + const dependencyTs: File = { path: `${dependecyLocation}/fns.ts`, content: `export function fn1() { } export function fn2() { } ` }; - const dependencyConfig: ts.projectSystem.File = { + const dependencyConfig: File = { path: `${dependecyLocation}/tsconfig.json`, content: JSON.stringify({ compilerOptions: { composite: true, declarationDir: "../decls" }, compileOnSave: true }) }; - const usageTs: ts.projectSystem.File = { + const usageTs: File = { path: `${usageLocation}/usage.ts`, content: `import { fn1, @@ -26,7 +29,7 @@ fn1(); fn2(); ` }; - const usageConfig: ts.projectSystem.File = { + const usageConfig: File = { path: `${usageLocation}/tsconfig.json`, content: JSON.stringify({ compileOnSave: true, @@ -40,126 +43,126 @@ fn2(); describe("when dependency project is not open", () => { describe("Of usageTs", () => { it("with initial file open, without specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs], session); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: usageTs.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: usageTs.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage", session); }); it("with initial file open, with specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs], session); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage with project", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage with project", session); }); it("with local change to dependency, without specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); host.writeFile(dependencyTs.path, `${dependencyTs.content}${localChange}`); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: usageTs.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: usageTs.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage and local change to dependency", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage and local change to dependency", session); }); it("with local change to dependency, with specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); host.writeFile(dependencyTs.path, `${dependencyTs.content}${localChange}`); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage with project and local change to dependency", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage with project and local change to dependency", session); }); it("with local change to usage, without specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); - const toLocation = ts.projectSystem.protocolToLocation(usageTs.content); + const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: usageTs.path, ...location, @@ -170,37 +173,37 @@ fn2(); }); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: usageTs.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: usageTs.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage and local change to usage", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage and local change to usage", session); }); it("with local change to usage, with specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); - const toLocation = ts.projectSystem.protocolToLocation(usageTs.content); + const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: usageTs.path, ...location, @@ -211,97 +214,97 @@ fn2(); }); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage with project and local change to usage", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage with project and local change to usage", session); }); it("with change to dependency, without specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); host.writeFile(dependencyTs.path, `${dependencyTs.content}${change}`); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: usageTs.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: usageTs.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage and change to depenedency", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage and change to depenedency", session); }); it("with change to dependency, with specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); host.writeFile(dependencyTs.path, `${dependencyTs.content}${change}`); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage with project and change to depenedency", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage with project and change to depenedency", session); }); it("with change to usage, without specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); - const toLocation = ts.projectSystem.protocolToLocation(usageTs.content); + const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: usageTs.path, ...location, @@ -312,37 +315,37 @@ fn2(); }); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: usageTs.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: usageTs.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage and change to usage", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage and change to usage", session); }); it("with change to usage, with specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); - const toLocation = ts.projectSystem.protocolToLocation(usageTs.content); + const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: usageTs.path, ...location, @@ -353,148 +356,148 @@ fn2(); }); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage with project and change to usage", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage with project and change to usage", session); }); }); describe("Of dependencyTs in usage project", () => { it("with initial file open, without specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs], session); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: dependencyTs.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency", session); }); it("with initial file open, with specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs], session); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency with project", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency with project", session); }); it("with local change to dependency, without specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); host.writeFile(dependencyTs.path, `${dependencyTs.content}${localChange}`); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: dependencyTs.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency and local change to dependency", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency and local change to dependency", session); }); it("with local change to dependency, with specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); host.writeFile(dependencyTs.path, `${dependencyTs.content}${localChange}`); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency with project and local change to dependency", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency with project and local change to dependency", session); }); it("with local change to usage, without specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); - const toLocation = ts.projectSystem.protocolToLocation(usageTs.content); + const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: usageTs.path, ...location, @@ -505,37 +508,37 @@ fn2(); }); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: dependencyTs.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency and local change to usage", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency and local change to usage", session); }); it("with local change to usage, with specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); - const toLocation = ts.projectSystem.protocolToLocation(usageTs.content); + const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: usageTs.path, ...location, @@ -546,97 +549,97 @@ fn2(); }); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency with project and local change to usage", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency with project and local change to usage", session); }); it("with change to dependency, without specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); host.writeFile(dependencyTs.path, `${dependencyTs.content}${change}`); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: dependencyTs.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency and change to dependency", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency and change to dependency", session); }); it("with change to dependency, with specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); host.writeFile(dependencyTs.path, `${dependencyTs.content}${change}`); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency with project and change to dependency", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency with project and change to dependency", session); }); it("with change to usage, without specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); - const toLocation = ts.projectSystem.protocolToLocation(usageTs.content); + const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: usageTs.path, ...location, @@ -647,37 +650,37 @@ fn2(); }); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: dependencyTs.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency and change to usage", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency and change to usage", session); }); it("with change to usage, with specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); - const toLocation = ts.projectSystem.protocolToLocation(usageTs.content); + const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: usageTs.path, ...location, @@ -688,23 +691,23 @@ fn2(); }); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency with project and change to usage", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency with project and change to usage", session); }); }); }); @@ -712,66 +715,66 @@ fn2(); describe("when the depedency file is open", () => { describe("Of usageTs", () => { it("with initial file open, without specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs, dependencyTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs, dependencyTs], session); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: usageTs.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: usageTs.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage", session); }); it("with initial file open, with specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs, dependencyTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs, dependencyTs], session); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage with project", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage with project", session); }); it("with local change to dependency, without specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs, dependencyTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs, dependencyTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); - const toLocation = ts.projectSystem.protocolToLocation(dependencyTs.content); + const toLocation = protocolToLocation(dependencyTs.content); const location = toLocation(dependencyTs.content.length); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: dependencyTs.path, ...location, @@ -782,37 +785,37 @@ fn2(); }); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: usageTs.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: usageTs.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage and local change to dependency", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage and local change to dependency", session); }); it("with local change to dependency, with specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs, dependencyTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs, dependencyTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); - const toLocation = ts.projectSystem.protocolToLocation(dependencyTs.content); + const toLocation = protocolToLocation(dependencyTs.content); const location = toLocation(dependencyTs.content.length); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: dependencyTs.path, ...location, @@ -823,37 +826,37 @@ fn2(); }); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage and local change to dependency with file", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage and local change to dependency with file", session); }); it("with local change to usage, without specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs, dependencyTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs, dependencyTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); - const toLocation = ts.projectSystem.protocolToLocation(usageTs.content); + const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: usageTs.path, ...location, @@ -864,37 +867,37 @@ fn2(); }); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: usageTs.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: usageTs.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage and local change to usage", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage and local change to usage", session); }); it("with local change to usage, with specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs, dependencyTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs, dependencyTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); - const toLocation = ts.projectSystem.protocolToLocation(usageTs.content); + const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: usageTs.path, ...location, @@ -905,37 +908,37 @@ fn2(); }); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage and local change to usage with project", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage and local change to usage with project", session); }); it("with change to dependency, without specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs, dependencyTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs, dependencyTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); - const toLocation = ts.projectSystem.protocolToLocation(dependencyTs.content); + const toLocation = protocolToLocation(dependencyTs.content); const location = toLocation(dependencyTs.content.length); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: dependencyTs.path, ...location, @@ -946,37 +949,37 @@ fn2(); }); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: usageTs.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: usageTs.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage and change to dependency", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage and change to dependency", session); }); it("with change to dependency, with specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs, dependencyTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs, dependencyTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); - const toLocation = ts.projectSystem.protocolToLocation(dependencyTs.content); + const toLocation = protocolToLocation(dependencyTs.content); const location = toLocation(dependencyTs.content.length); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: dependencyTs.path, ...location, @@ -987,37 +990,37 @@ fn2(); }); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage with project and change to dependency", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage with project and change to dependency", session); }); it("with change to usage, without specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs, dependencyTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs, dependencyTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); - const toLocation = ts.projectSystem.protocolToLocation(usageTs.content); + const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: usageTs.path, ...location, @@ -1028,37 +1031,37 @@ fn2(); }); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: usageTs.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: usageTs.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage and change to usage", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage and change to usage", session); }); it("with change to usage, with specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs, dependencyTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs, dependencyTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); - const toLocation = ts.projectSystem.protocolToLocation(usageTs.content); + const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: usageTs.path, ...location, @@ -1069,63 +1072,63 @@ fn2(); }); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: usageTs.path, projectFileName: usageConfig.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage with project and change to usage", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage with project and change to usage", session); }); }); describe("Of dependencyTs in usage project", () => { it("with initial file open, with specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs, dependencyTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs, dependencyTs], session); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with usage project", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with usage project", session); }); it("with local change to dependency, with specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs, dependencyTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs, dependencyTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); - const toLocation = ts.projectSystem.protocolToLocation(dependencyTs.content); + const toLocation = protocolToLocation(dependencyTs.content); const location = toLocation(dependencyTs.content.length); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: dependencyTs.path, ...location, @@ -1136,37 +1139,37 @@ fn2(); }); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with usage project and local change to dependency", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with usage project and local change to dependency", session); }); it("with local change to usage, with specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs, dependencyTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs, dependencyTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); - const toLocation = ts.projectSystem.protocolToLocation(usageTs.content); + const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: usageTs.path, ...location, @@ -1177,37 +1180,37 @@ fn2(); }); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with usage project and local change to usage", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with usage project and local change to usage", session); }); it("with change to dependency, with specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs, dependencyTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs, dependencyTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); - const toLocation = ts.projectSystem.protocolToLocation(dependencyTs.content); + const toLocation = protocolToLocation(dependencyTs.content); const location = toLocation(dependencyTs.content.length); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: dependencyTs.path, ...location, @@ -1218,37 +1221,37 @@ fn2(); }); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with usage project and change to dependency", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with usage project and change to dependency", session); }); it("with change to usage, with specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs, dependencyTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs, dependencyTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); - const toLocation = ts.projectSystem.protocolToLocation(usageTs.content); + const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: usageTs.path, ...location, @@ -1259,88 +1262,88 @@ fn2(); }); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with usage project and change to usage", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with usage project and change to usage", session); }); }); describe("Of dependencyTs", () => { it("with initial file open, without specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs, dependencyTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs, dependencyTs], session); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: dependencyTs.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency", session); }); it("with initial file open, with specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs, dependencyTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs, dependencyTs], session); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with project", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with project", session); }); it("with local change to dependency, without specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs, dependencyTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs, dependencyTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); - const toLocation = ts.projectSystem.protocolToLocation(dependencyTs.content); + const toLocation = protocolToLocation(dependencyTs.content); const location = toLocation(dependencyTs.content.length); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: dependencyTs.path, ...location, @@ -1351,37 +1354,37 @@ fn2(); }); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: dependencyTs.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency and local change to dependency", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency and local change to dependency", session); }); it("with local change to dependency, with specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs, dependencyTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs, dependencyTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); - const toLocation = ts.projectSystem.protocolToLocation(dependencyTs.content); + const toLocation = protocolToLocation(dependencyTs.content); const location = toLocation(dependencyTs.content.length); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: dependencyTs.path, ...location, @@ -1392,37 +1395,37 @@ fn2(); }); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with project and local change to dependency", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with project and local change to dependency", session); }); it("with local change to usage, without specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs, dependencyTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs, dependencyTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); - const toLocation = ts.projectSystem.protocolToLocation(usageTs.content); + const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: usageTs.path, ...location, @@ -1433,37 +1436,37 @@ fn2(); }); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: dependencyTs.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency and local change to usage", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency and local change to usage", session); }); it("with local change to usage, with specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs, dependencyTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs, dependencyTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); - const toLocation = ts.projectSystem.protocolToLocation(usageTs.content); + const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: usageTs.path, ...location, @@ -1474,37 +1477,37 @@ fn2(); }); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with project and local change to usage", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with project and local change to usage", session); }); it("with change to dependency, without specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs, dependencyTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs, dependencyTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); - const toLocation = ts.projectSystem.protocolToLocation(dependencyTs.content); + const toLocation = protocolToLocation(dependencyTs.content); const location = toLocation(dependencyTs.content.length); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: dependencyTs.path, ...location, @@ -1515,37 +1518,37 @@ fn2(); }); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: dependencyTs.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency and change to dependency", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency and change to dependency", session); }); it("with change to dependency, with specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs, dependencyTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs, dependencyTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); - const toLocation = ts.projectSystem.protocolToLocation(dependencyTs.content); + const toLocation = protocolToLocation(dependencyTs.content); const location = toLocation(dependencyTs.content.length); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: dependencyTs.path, ...location, @@ -1556,37 +1559,37 @@ fn2(); }); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with project and change to dependency", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with project and change to dependency", session); }); it("with change to usage, without specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs, dependencyTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs, dependencyTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); - const toLocation = ts.projectSystem.protocolToLocation(usageTs.content); + const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: usageTs.path, ...location, @@ -1597,37 +1600,37 @@ fn2(); }); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: dependencyTs.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency and change to usage", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency and change to usage", session); }); it("with change to usage, with specifying project file", () => { - const host = ts.projectSystem.createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([usageTs, dependencyTs], session); + const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([usageTs, dependencyTs], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path } }); - const toLocation = ts.projectSystem.protocolToLocation(usageTs.content); + const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: usageTs.path, ...location, @@ -1638,23 +1641,23 @@ fn2(); }); // Verify CompileOnSaveAffectedFileList - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveAffectedFileList, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } }); // Verify CompileOnSaveEmit - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } }); // Verify EmitOutput - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.EmitOutput, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.EmitOutput, arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with project and change to usage", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with project and change to usage", session); }); }); }); @@ -1662,8 +1665,8 @@ fn2(); describe("unittests:: tsserver:: with project references and compile on save with external projects", () => { it("compile on save emits same output as project build", () => { - const tsbaseJson: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/tsbase.json`, + const tsbaseJson: File = { + path: `/user/username/projects/myproject/tsbase.json`, content: JSON.stringify({ compileOnSave: true, compilerOptions: { @@ -1672,8 +1675,8 @@ describe("unittests:: tsserver:: with project references and compile on save wit } }) }; - const buttonClass = `${ts.tscWatch.projectRoot}/buttonClass`; - const buttonConfig: ts.projectSystem.File = { + const buttonClass = `/user/username/projects/myproject/buttonClass`; + const buttonConfig: File = { path: `${buttonClass}/tsconfig.json`, content: JSON.stringify({ extends: "../tsbase.json", @@ -1683,7 +1686,7 @@ describe("unittests:: tsserver:: with project references and compile on save wit files: ["Source.ts"] }) }; - const buttonSource: ts.projectSystem.File = { + const buttonSource: File = { path: `${buttonClass}/Source.ts`, content: `module Hmi { export class Button { @@ -1693,8 +1696,8 @@ describe("unittests:: tsserver:: with project references and compile on save wit }` }; - const siblingClass = `${ts.tscWatch.projectRoot}/SiblingClass`; - const siblingConfig: ts.projectSystem.File = { + const siblingClass = `/user/username/projects/myproject/SiblingClass`; + const siblingConfig: File = { path: `${siblingClass}/tsconfig.json`, content: JSON.stringify({ extends: "../tsbase.json", @@ -1707,7 +1710,7 @@ describe("unittests:: tsserver:: with project references and compile on save wit files: ["Source.ts"] }) }; - const siblingSource: ts.projectSystem.File = { + const siblingSource: File = { path: `${siblingClass}/Source.ts`, content: `module Hmi { export class Sibling { @@ -1716,21 +1719,21 @@ describe("unittests:: tsserver:: with project references and compile on save wit } }` }; - const host = ts.projectSystem.createServerHost([ts.projectSystem.libFile, tsbaseJson, buttonConfig, buttonSource, siblingConfig, siblingSource], { useCaseSensitiveFileNames: true }); + const host = createServerHost([libFile, tsbaseJson, buttonConfig, buttonSource, siblingConfig, siblingSource], { useCaseSensitiveFileNames: true }); // ts build should succeed - ts.tscWatch.ensureErrorFreeBuild(host, [siblingConfig.path]); + ensureErrorFreeBuild(host, [siblingConfig.path]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([siblingSource], session); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([siblingSource], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompileOnSaveEmitFile, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: siblingSource.path, projectFileName: siblingConfig.path } }); - ts.projectSystem.baselineTsserverLogs("projectReferenceCompileOnSave", "compile on save emits same output as project build with external project", session); + baselineTsserverLogs("projectReferenceCompileOnSave", "compile on save emits same output as project build with external project", session); }); }); \ No newline at end of file diff --git a/src/testRunner/unittests/tsserver/projectReferenceErrors.ts b/src/testRunner/unittests/tsserver/projectReferenceErrors.ts index 1dc9e6e0201..7d25ffdfb40 100644 --- a/src/testRunner/unittests/tsserver/projectReferenceErrors.ts +++ b/src/testRunner/unittests/tsserver/projectReferenceErrors.ts @@ -1,20 +1,21 @@ -import * as ts from "../../_namespaces/ts"; +import { File } from "../virtualFileSystemWithWatch"; +import { GetErrForProjectDiagnostics, verifyGetErrScenario } from "./helpers"; describe("unittests:: tsserver:: with project references and error reporting", () => { - const dependecyLocation = `${ts.tscWatch.projectRoot}/dependency`; - const usageLocation = `${ts.tscWatch.projectRoot}/usage`; + const dependecyLocation = `/user/username/projects/myproject/dependency`; + const usageLocation = `/user/username/projects/myproject/usage`; - function verifyUsageAndDependency(scenario: string, dependencyTs: ts.projectSystem.File, dependencyConfig: ts.projectSystem.File, usageTs: ts.projectSystem.File, usageConfig: ts.projectSystem.File) { - function usageProjectDiagnostics(): ts.projectSystem.GetErrForProjectDiagnostics { + function verifyUsageAndDependency(scenario: string, dependencyTs: File, dependencyConfig: File, usageTs: File, usageConfig: File) { + function usageProjectDiagnostics(): GetErrForProjectDiagnostics { return { project: usageTs, files: [usageTs, dependencyTs] }; } - function dependencyProjectDiagnostics(): ts.projectSystem.GetErrForProjectDiagnostics { + function dependencyProjectDiagnostics(): GetErrForProjectDiagnostics { return { project: dependencyTs, files: [dependencyTs] }; } describe("when dependency project is not open", () => { - ts.projectSystem.verifyGetErrScenario({ + verifyGetErrScenario({ scenario: "projectReferenceErrors", subScenario: `${scenario} when dependency project is not open`, allFiles: () => [dependencyTs, dependencyConfig, usageTs, usageConfig], @@ -39,7 +40,7 @@ describe("unittests:: tsserver:: with project references and error reporting", ( }); describe("when the depedency file is open", () => { - ts.projectSystem.verifyGetErrScenario({ + verifyGetErrScenario({ scenario: "projectReferenceErrors", subScenario: `${scenario} when the depedency file is open`, allFiles: () => [dependencyTs, dependencyConfig, usageTs, usageConfig], @@ -63,7 +64,7 @@ describe("unittests:: tsserver:: with project references and error reporting", ( } describe("with module scenario", () => { - const dependencyTs: ts.projectSystem.File = { + const dependencyTs: File = { path: `${dependecyLocation}/fns.ts`, content: `export function fn1() { } export function fn2() { } @@ -72,11 +73,11 @@ export function fn2() { } // Error in dependency ts file export let x: string = 10;` }; - const dependencyConfig: ts.projectSystem.File = { + const dependencyConfig: File = { path: `${dependecyLocation}/tsconfig.json`, content: JSON.stringify({ compilerOptions: { composite: true, declarationDir: "../decls" } }) }; - const usageTs: ts.projectSystem.File = { + const usageTs: File = { path: `${usageLocation}/usage.ts`, content: `import { fn1, @@ -88,7 +89,7 @@ fn2(); fnErr(); ` }; - const usageConfig: ts.projectSystem.File = { + const usageConfig: File = { path: `${usageLocation}/tsconfig.json`, content: JSON.stringify({ compilerOptions: { composite: true }, @@ -99,7 +100,7 @@ fnErr(); }); describe("with non module --out", () => { - const dependencyTs: ts.projectSystem.File = { + const dependencyTs: File = { path: `${dependecyLocation}/fns.ts`, content: `function fn1() { } function fn2() { } @@ -108,18 +109,18 @@ function fn2() { } // Error in dependency ts file let x: string = 10;` }; - const dependencyConfig: ts.projectSystem.File = { + const dependencyConfig: File = { path: `${dependecyLocation}/tsconfig.json`, content: JSON.stringify({ compilerOptions: { composite: true, outFile: "../dependency.js" } }) }; - const usageTs: ts.projectSystem.File = { + const usageTs: File = { path: `${usageLocation}/usage.ts`, content: `fn1(); fn2(); fnErr(); ` }; - const usageConfig: ts.projectSystem.File = { + const usageConfig: File = { path: `${usageLocation}/tsconfig.json`, content: JSON.stringify({ compilerOptions: { composite: true, outFile: "../usage.js" }, diff --git a/src/testRunner/unittests/tsserver/projectReferences.ts b/src/testRunner/unittests/tsserver/projectReferences.ts index d03e2167deb..8fa087a7a7c 100644 --- a/src/testRunner/unittests/tsserver/projectReferences.ts +++ b/src/testRunner/unittests/tsserver/projectReferences.ts @@ -1,12 +1,14 @@ import * as ts from "../../_namespaces/ts"; -import { createHostWithSolutionBuild } from "./helpers"; +import { baselineTsserverLogs, checkProjectActualFiles, createHostWithSolutionBuild, createLoggerWithInMemoryLogs, createProjectService, createSession, makeReferenceItem, openFilesForSession, protocolFileLocationFromSubstring, protocolLocationFromSubstring, verifyGetErrRequest } from "./helpers"; +import { createServerHost, File, getTsBuildProjectFile, getTsBuildProjectFilePath, libFile, SymLink } from "../virtualFileSystemWithWatch"; +import { solutionBuildWithBaseline } from "../tscWatch/helpers"; describe("unittests:: tsserver:: with project references and tsbuild", () => { describe("with container project", () => { - function getProjectFiles(project: string): [ts.projectSystem.File, ts.projectSystem.File] { + function getProjectFiles(project: string): [File, File] { return [ - ts.TestFSWithWatch.getTsBuildProjectFile(project, "tsconfig.json"), - ts.TestFSWithWatch.getTsBuildProjectFile(project, "index.ts"), + getTsBuildProjectFile(project, "tsconfig.json"), + getTsBuildProjectFile(project, "index.ts"), ]; } @@ -14,72 +16,72 @@ describe("unittests:: tsserver:: with project references and tsbuild", () => { const containerLib = getProjectFiles("container/lib"); const containerExec = getProjectFiles("container/exec"); const containerCompositeExec = getProjectFiles("container/compositeExec"); - const containerConfig = ts.TestFSWithWatch.getTsBuildProjectFile(project, "tsconfig.json"); - const files = [ts.projectSystem.libFile, ...containerLib, ...containerExec, ...containerCompositeExec, containerConfig]; + const containerConfig = getTsBuildProjectFile(project, "tsconfig.json"); + const files = [libFile, ...containerLib, ...containerExec, ...containerCompositeExec, containerConfig]; it("does not error on container only project", () => { const host = createHostWithSolutionBuild(files, [containerConfig.path]); // Open external project for the folder - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); const service = session.getProjectService(); service.openExternalProjects([{ - projectFileName: ts.TestFSWithWatch.getTsBuildProjectFilePath(project, project), + projectFileName: getTsBuildProjectFilePath(project, project), rootFiles: files.map(f => ({ fileName: f.path })), options: {} }]); files.forEach(f => { - const args: ts.projectSystem.protocol.FileRequestArgs = { + const args: ts.server.protocol.FileRequestArgs = { file: f.path, projectFileName: ts.endsWith(f.path, "tsconfig.json") ? f.path : undefined }; - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.SyntacticDiagnosticsSync, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.SyntacticDiagnosticsSync, arguments: args }); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.SemanticDiagnosticsSync, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.SemanticDiagnosticsSync, arguments: args }); }); const containerProject = service.configuredProjects.get(containerConfig.path)!; - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.CompilerOptionsDiagnosticsFull, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.CompilerOptionsDiagnosticsFull, arguments: { projectFileName: containerProject.projectName } }); - ts.projectSystem.baselineTsserverLogs("projectReferences", `does not error on container only project`, session); + baselineTsserverLogs("projectReferences", `does not error on container only project`, session); }); it("can successfully find references with --out options", () => { const host = createHostWithSolutionBuild(files, [containerConfig.path]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([containerCompositeExec[1]], session); - const myConstStart = ts.projectSystem.protocolLocationFromSubstring(containerCompositeExec[1].content, "myConst"); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Rename, + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([containerCompositeExec[1]], session); + const myConstStart = protocolLocationFromSubstring(containerCompositeExec[1].content, "myConst"); + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Rename, arguments: { file: containerCompositeExec[1].path, ...myConstStart } }); - ts.projectSystem.baselineTsserverLogs("projectReferences", `can successfully find references with out option`, session); + baselineTsserverLogs("projectReferences", `can successfully find references with out option`, session); }); it("ancestor and project ref management", () => { - const tempFile: ts.projectSystem.File = { + const tempFile: File = { path: `/user/username/projects/temp/temp.ts`, content: "let x = 10" }; const host = createHostWithSolutionBuild(files.concat([tempFile]), [containerConfig.path]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([containerCompositeExec[1]], session); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([containerCompositeExec[1]], session); const service = session.getProjectService(); // Open temp file and verify all projects alive - ts.projectSystem.openFilesForSession([tempFile], session); + openFilesForSession([tempFile], session); // Ref projects are loaded after as part of this command - const locationOfMyConst = ts.projectSystem.protocolLocationFromSubstring(containerCompositeExec[1].content, "myConst"); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Rename, + const locationOfMyConst = protocolLocationFromSubstring(containerCompositeExec[1].content, "myConst"); + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Rename, arguments: { file: containerCompositeExec[1].path, ...locationOfMyConst @@ -88,20 +90,20 @@ describe("unittests:: tsserver:: with project references and tsbuild", () => { // Open temp file and verify all projects alive service.closeClientFile(tempFile.path); - ts.projectSystem.openFilesForSession([tempFile], session); + openFilesForSession([tempFile], session); // Close all files and open temp file, only inferred project should be alive service.closeClientFile(containerCompositeExec[1].path); service.closeClientFile(tempFile.path); - ts.projectSystem.openFilesForSession([tempFile], session); - ts.projectSystem.baselineTsserverLogs("projectReferences", `ancestor and project ref management`, session); + openFilesForSession([tempFile], session); + baselineTsserverLogs("projectReferences", `ancestor and project ref management`, session); }); }); describe("when root file is file from referenced project", () => { function verify(disableSourceOfProjectReferenceRedirect: boolean) { const projectLocation = `/user/username/projects/project`; - const commonConfig: ts.projectSystem.File = { + const commonConfig: File = { path: `${projectLocation}/src/common/tsconfig.json`, content: JSON.stringify({ compilerOptions: { @@ -114,12 +116,12 @@ describe("unittests:: tsserver:: with project references and tsbuild", () => { include: ["./**/*"] }) }; - const keyboardTs: ts.projectSystem.File = { + const keyboardTs: File = { path: `${projectLocation}/src/common/input/keyboard.ts`, content: `function bar() { return "just a random function so .d.ts location doesnt match"; } export function evaluateKeyboardEvent() { }` }; - const keyboardTestTs: ts.projectSystem.File = { + const keyboardTestTs: File = { path: `${projectLocation}/src/common/input/keyboard.test.ts`, content: `import { evaluateKeyboardEvent } from 'common/input/keyboard'; function testEvaluateKeyboardEvent() { @@ -127,7 +129,7 @@ function testEvaluateKeyboardEvent() { } ` }; - const srcConfig: ts.projectSystem.File = { + const srcConfig: File = { path: `${projectLocation}/src/tsconfig.json`, content: JSON.stringify({ compilerOptions: { @@ -147,7 +149,7 @@ function testEvaluateKeyboardEvent() { ] }) }; - const terminalTs: ts.projectSystem.File = { + const terminalTs: File = { path: `${projectLocation}/src/terminal.ts`, content: `import { evaluateKeyboardEvent } from 'common/input/keyboard'; function foo() { @@ -156,28 +158,28 @@ function foo() { ` }; const host = createHostWithSolutionBuild( - [commonConfig, keyboardTs, keyboardTestTs, srcConfig, terminalTs, ts.projectSystem.libFile], + [commonConfig, keyboardTs, keyboardTestTs, srcConfig, terminalTs, libFile], [srcConfig.path] ); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([keyboardTs, terminalTs], session); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([keyboardTs, terminalTs], session); const searchStr = "evaluateKeyboardEvent"; const importStr = `import { evaluateKeyboardEvent } from 'common/input/keyboard';`; - const result = session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.References, - arguments: ts.projectSystem.protocolFileLocationFromSubstring(keyboardTs, searchStr) - }).response as ts.projectSystem.protocol.ReferencesResponseBody; + const result = session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.References, + arguments: protocolFileLocationFromSubstring(keyboardTs, searchStr) + }).response as ts.server.protocol.ReferencesResponseBody; assert.deepEqual(result, { refs: [ - ts.projectSystem.makeReferenceItem({ + makeReferenceItem({ file: keyboardTs, text: searchStr, contextText: `export function evaluateKeyboardEvent() { }`, isDefinition: true, lineText: `export function evaluateKeyboardEvent() { }` }), - ts.projectSystem.makeReferenceItem({ + makeReferenceItem({ file: keyboardTestTs, text: searchStr, contextText: importStr, @@ -185,14 +187,14 @@ function foo() { isWriteAccess: true, lineText: importStr }), - ts.projectSystem.makeReferenceItem({ + makeReferenceItem({ file: keyboardTestTs, text: searchStr, options: { index: 1 }, isDefinition: false, lineText: ` return evaluateKeyboardEvent();` }), - ts.projectSystem.makeReferenceItem({ + makeReferenceItem({ file: terminalTs, text: searchStr, contextText: importStr, @@ -200,7 +202,7 @@ function foo() { isWriteAccess: true, lineText: importStr }), - ts.projectSystem.makeReferenceItem({ + makeReferenceItem({ file: terminalTs, text: searchStr, options: { index: 1 }, @@ -209,10 +211,10 @@ function foo() { }), ], symbolName: searchStr, - symbolStartOffset: ts.projectSystem.protocolLocationFromSubstring(keyboardTs.content, searchStr).offset, + symbolStartOffset: protocolLocationFromSubstring(keyboardTs.content, searchStr).offset, symbolDisplayString: "function evaluateKeyboardEvent(): void" }); - ts.projectSystem.baselineTsserverLogs("projectReferences", `root file is file from referenced project${disableSourceOfProjectReferenceRedirect ? " and using declaration maps" : ""}`, session); + baselineTsserverLogs("projectReferences", `root file is file from referenced project${disableSourceOfProjectReferenceRedirect ? " and using declaration maps" : ""}`, session); } it(`when using declaration file maps to navigate between projects`, () => { @@ -224,8 +226,8 @@ function foo() { }); it("reusing d.ts files from composite and non composite projects", () => { - const configA: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/compositea/tsconfig.json`, + const configA: File = { + path: `/user/username/projects/myproject/compositea/tsconfig.json`, content: JSON.stringify({ compilerOptions: { composite: true, @@ -236,28 +238,28 @@ function foo() { } }) }; - const aTs: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/compositea/a.ts`, + const aTs: File = { + path: `/user/username/projects/myproject/compositea/a.ts`, content: `import { b } from "@ref/compositeb/b";` }; - const a2Ts: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/compositea/a2.ts`, + const a2Ts: File = { + path: `/user/username/projects/myproject/compositea/a2.ts`, content: `export const x = 10;` }; - const configB: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/compositeb/tsconfig.json`, + const configB: File = { + path: `/user/username/projects/myproject/compositeb/tsconfig.json`, content: configA.content }; - const bTs: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/compositeb/b.ts`, + const bTs: File = { + path: `/user/username/projects/myproject/compositeb/b.ts`, content: "export function b() {}" }; - const bDts: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/dist/compositeb/b.d.ts`, + const bDts: File = { + path: `/user/username/projects/myproject/dist/compositeb/b.d.ts`, content: "export declare function b(): void;" }; - const configC: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/compositec/tsconfig.json`, + const configC: File = { + path: `/user/username/projects/myproject/compositec/tsconfig.json`, content: JSON.stringify({ compilerOptions: { composite: true, @@ -269,27 +271,27 @@ function foo() { references: [{ path: "../compositeb" }] }) }; - const cTs: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/compositec/c.ts`, + const cTs: File = { + path: `/user/username/projects/myproject/compositec/c.ts`, content: aTs.content }; - const files = [ts.projectSystem.libFile, aTs, a2Ts, configA, bDts, bTs, configB, cTs, configC]; - const host = ts.projectSystem.createServerHost(files); - const service = ts.projectSystem.createProjectService(host); + const files = [libFile, aTs, a2Ts, configA, bDts, bTs, configB, cTs, configC]; + const host = createServerHost(files); + const service = createProjectService(host); service.openClientFile(aTs.path); service.checkNumberOfProjects({ configuredProjects: 1 }); // project A referencing b.d.ts without project reference const projectA = service.configuredProjects.get(configA.path)!; assert.isDefined(projectA); - ts.projectSystem.checkProjectActualFiles(projectA, [aTs.path, a2Ts.path, bDts.path, ts.projectSystem.libFile.path, configA.path]); + checkProjectActualFiles(projectA, [aTs.path, a2Ts.path, bDts.path, libFile.path, configA.path]); // reuses b.d.ts but sets the path and resolved path since projectC has project references // as the real resolution was to b.ts service.openClientFile(cTs.path); service.checkNumberOfProjects({ configuredProjects: 2 }); const projectC = service.configuredProjects.get(configC.path)!; - ts.projectSystem.checkProjectActualFiles(projectC, [cTs.path, bTs.path, ts.projectSystem.libFile.path, configC.path]); + checkProjectActualFiles(projectC, [cTs.path, bTs.path, libFile.path, configC.path]); // Now new project for project A tries to reuse b but there is no filesByName mapping for b's source location host.writeFile(a2Ts.path, `${a2Ts.content}export const y = 30;`); @@ -299,11 +301,11 @@ function foo() { describe("when references are monorepo like with symlinks", () => { interface Packages { - bPackageJson: ts.projectSystem.File; - aTest: ts.projectSystem.File; - bFoo: ts.projectSystem.File; - bBar: ts.projectSystem.File; - bSymlink: ts.projectSystem.SymLink; + bPackageJson: File; + aTest: File; + bFoo: File; + bBar: File; + bSymlink: SymLink; } function verifySymlinkScenario(scenario: string, packages: () => Packages) { describe(`${scenario}: when solution is not built`, () => { @@ -330,17 +332,17 @@ function foo() { function verifySession(scenario: string, { bPackageJson, aTest, bFoo, bBar, bSymlink }: Packages, alreadyBuilt: boolean, extraOptions: ts.CompilerOptions) { const aConfig = config("A", extraOptions, ["../B"]); const bConfig = config("B", extraOptions); - const files = [ts.projectSystem.libFile, bPackageJson, aConfig, bConfig, aTest, bFoo, bBar, bSymlink]; + const files = [libFile, bPackageJson, aConfig, bConfig, aTest, bFoo, bBar, bSymlink]; const host = alreadyBuilt ? createHostWithSolutionBuild(files, [aConfig.path]) : - ts.projectSystem.createServerHost(files); + createServerHost(files); // Create symlink in node module - const session = ts.projectSystem.createSession(host, { canUseEvents: true, logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([aTest], session); - ts.projectSystem.verifyGetErrRequest({ session, host, files: [aTest] }); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.UpdateOpen, + const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([aTest], session); + verifyGetErrRequest({ session, host, files: [aTest] }); + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.UpdateOpen, arguments: { changedFiles: [{ fileName: aTest.path, @@ -352,13 +354,13 @@ function foo() { }] } }); - ts.projectSystem.verifyGetErrRequest({ session, host, files: [aTest] }); - ts.projectSystem.baselineTsserverLogs("projectReferences", `monorepo like with symlinks ${scenario} and solution is ${alreadyBuilt ? "built" : "not built"}${extraOptions.preserveSymlinks ? " with preserveSymlinks" : ""}`, session); + verifyGetErrRequest({ session, host, files: [aTest] }); + baselineTsserverLogs("projectReferences", `monorepo like with symlinks ${scenario} and solution is ${alreadyBuilt ? "built" : "not built"}${extraOptions.preserveSymlinks ? " with preserveSymlinks" : ""}`, session); } - function config(packageName: string, extraOptions: ts.CompilerOptions, references?: string[]): ts.projectSystem.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", @@ -372,9 +374,9 @@ function foo() { }; } - function file(packageName: string, fileName: string, content: string): ts.projectSystem.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 }; } @@ -382,7 +384,7 @@ function foo() { function verifyMonoRepoLike(scope = "") { verifySymlinkScenario(`when packageJson has types field and has index.ts${scope ? " with scoped package" : ""}`, () => ({ 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" @@ -396,14 +398,14 @@ 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` } })); verifySymlinkScenario(`when referencing file from subFolder${scope ? " with scoped package" : ""}`, () => ({ 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'; @@ -414,8 +416,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` } })); } @@ -429,8 +431,8 @@ bar(); }); it("when the referenced projects have allowJs and emitDeclarationOnly", () => { - const compositeConfig: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/packages/emit-composite/tsconfig.json`, + const compositeConfig: File = { + path: `/user/username/projects/myproject/packages/emit-composite/tsconfig.json`, content: JSON.stringify({ compilerOptions: { composite: true, @@ -442,8 +444,8 @@ bar(); include: ["src"] }) }; - const compositePackageJson: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/packages/emit-composite/package.json`, + const compositePackageJson: File = { + path: `/user/username/projects/myproject/packages/emit-composite/package.json`, content: JSON.stringify({ name: "emit-composite", version: "1.0.0", @@ -451,15 +453,15 @@ bar(); typings: "lib/index.d.ts" }) }; - const compositeIndex: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/packages/emit-composite/src/index.js`, + const compositeIndex: File = { + path: `/user/username/projects/myproject/packages/emit-composite/src/index.js`, content: `const testModule = require('./testModule'); module.exports = { ...testModule }` }; - const compositeTestModule: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/packages/emit-composite/src/testModule.js`, + const compositeTestModule: File = { + path: `/user/username/projects/myproject/packages/emit-composite/src/testModule.js`, content: `/** * @param {string} arg */ @@ -469,33 +471,33 @@ module.exports = { testCompositeFunction }` }; - const consumerConfig: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/packages/consumer/tsconfig.json`, + const consumerConfig: File = { + path: `/user/username/projects/myproject/packages/consumer/tsconfig.json`, content: JSON.stringify({ include: ["src"], references: [{ path: "../emit-composite" }] }) }; - const consumerIndex: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/packages/consumer/src/index.ts`, + const consumerIndex: File = { + path: `/user/username/projects/myproject/packages/consumer/src/index.ts`, content: `import { testCompositeFunction } from 'emit-composite'; testCompositeFunction('why hello there'); testCompositeFunction('why hello there', 42);` }; - const symlink: ts.projectSystem.SymLink = { - path: `${ts.tscWatch.projectRoot}/node_modules/emit-composite`, - symLink: `${ts.tscWatch.projectRoot}/packages/emit-composite` + const symlink: SymLink = { + path: `/user/username/projects/myproject/node_modules/emit-composite`, + symLink: `/user/username/projects/myproject/packages/emit-composite` }; - const host = ts.projectSystem.createServerHost([ts.projectSystem.libFile, compositeConfig, compositePackageJson, compositeIndex, compositeTestModule, consumerConfig, consumerIndex, symlink], { useCaseSensitiveFileNames: true }); - const session = ts.projectSystem.createSession(host, { canUseEvents: true, logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([consumerIndex], session); - ts.projectSystem.verifyGetErrRequest({ host, session, files: [consumerIndex] }); - ts.projectSystem.baselineTsserverLogs("projectReferences", `when the referenced projects have allowJs and emitDeclarationOnly`, session); + const host = createServerHost([libFile, compositeConfig, compositePackageJson, compositeIndex, compositeTestModule, consumerConfig, consumerIndex, symlink], { useCaseSensitiveFileNames: true }); + const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([consumerIndex], session); + verifyGetErrRequest({ host, session, files: [consumerIndex] }); + baselineTsserverLogs("projectReferences", `when the referenced projects have allowJs and emitDeclarationOnly`, session); }); it("when finding local reference doesnt load ancestor/sibling projects", () => { const solutionLocation = "/user/username/projects/solution"; - const solution: ts.projectSystem.File = { + const solution: File = { path: `${solutionLocation}/tsconfig.json`, content: JSON.stringify({ files: [], @@ -506,7 +508,7 @@ testCompositeFunction('why hello there', 42);` ] }) }; - const compilerConfig: ts.projectSystem.File = { + const compilerConfig: File = { path: `${solutionLocation}/compiler/tsconfig.json`, content: JSON.stringify({ compilerOptions: { @@ -516,7 +518,7 @@ testCompositeFunction('why hello there', 42);` files: ["./types.ts", "./program.ts"] }) }; - const typesFile: ts.projectSystem.File = { + const typesFile: File = { path: `${solutionLocation}/compiler/types.ts`, content: ` namespace ts { @@ -525,7 +527,7 @@ testCompositeFunction('why hello there', 42);` } }` }; - const programFile: ts.projectSystem.File = { + const programFile: File = { path: `${solutionLocation}/compiler/program.ts`, content: ` namespace ts { @@ -535,7 +537,7 @@ testCompositeFunction('why hello there', 42);` function getSourceFile() { return "something"; } }` }; - const servicesConfig: ts.projectSystem.File = { + const servicesConfig: File = { path: `${solutionLocation}/services/tsconfig.json`, content: JSON.stringify({ compilerOptions: { @@ -547,7 +549,7 @@ testCompositeFunction('why hello there', 42);` ] }) }; - const servicesFile: ts.projectSystem.File = { + const servicesFile: File = { path: `${solutionLocation}/services/services.ts`, content: ` namespace ts { @@ -555,30 +557,30 @@ testCompositeFunction('why hello there', 42);` }` }; - const files = [ts.projectSystem.libFile, solution, compilerConfig, typesFile, programFile, servicesConfig, servicesFile, ts.projectSystem.libFile]; - const host = ts.projectSystem.createServerHost(files); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([programFile], session); + const files = [libFile, solution, compilerConfig, typesFile, programFile, servicesConfig, servicesFile, libFile]; + const host = createServerHost(files); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([programFile], session); // Find all references for getSourceFile // Shouldnt load more projects - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.References, - arguments: ts.projectSystem.protocolFileLocationFromSubstring(programFile, "getSourceFile", { index: 1 }) + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.References, + arguments: protocolFileLocationFromSubstring(programFile, "getSourceFile", { index: 1 }) }); // Find all references for getSourceFiles // Should load more projects - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.References, - arguments: ts.projectSystem.protocolFileLocationFromSubstring(programFile, "getSourceFiles") + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.References, + arguments: protocolFileLocationFromSubstring(programFile, "getSourceFiles") }); - ts.projectSystem.baselineTsserverLogs("projectReferences", `finding local reference doesnt load ancestor/sibling projects`, session); + baselineTsserverLogs("projectReferences", `finding local reference doesnt load ancestor/sibling projects`, session); }); it("when finding references in overlapping projects", () => { const solutionLocation = "/user/username/projects/solution"; - const solutionConfig: ts.projectSystem.File = { + const solutionConfig: File = { path: `${solutionLocation}/tsconfig.json`, content: JSON.stringify({ files: [], @@ -591,7 +593,7 @@ testCompositeFunction('why hello there', 42);` ] }) }; - const aConfig: ts.projectSystem.File = { + const aConfig: File = { path: `${solutionLocation}/a/tsconfig.json`, content: JSON.stringify({ compilerOptions: { @@ -601,7 +603,7 @@ testCompositeFunction('why hello there', 42);` files: ["./index.ts"] }) }; - const aFile: ts.projectSystem.File = { + const aFile: File = { path: `${solutionLocation}/a/index.ts`, content: ` export interface I { @@ -609,7 +611,7 @@ testCompositeFunction('why hello there', 42);` }` }; - const bConfig: ts.projectSystem.File = { + const bConfig: File = { path: `${solutionLocation}/b/tsconfig.json`, content: JSON.stringify({ compilerOptions: { @@ -621,7 +623,7 @@ testCompositeFunction('why hello there', 42);` ] }) }; - const bFile: ts.projectSystem.File = { + const bFile: File = { path: `${solutionLocation}/b/index.ts`, content: ` import { I } from "../a"; @@ -631,7 +633,7 @@ testCompositeFunction('why hello there', 42);` }` }; - const cConfig: ts.projectSystem.File = { + const cConfig: File = { path: `${solutionLocation}/c/tsconfig.json`, content: JSON.stringify({ compilerOptions: { @@ -643,7 +645,7 @@ testCompositeFunction('why hello there', 42);` ] }) }; - const cFile: ts.projectSystem.File = { + const cFile: File = { path: `${solutionLocation}/c/index.ts`, content: ` import { I } from "../a"; @@ -653,7 +655,7 @@ testCompositeFunction('why hello there', 42);` ` }; - const dConfig: ts.projectSystem.File = { + const dConfig: File = { path: `${solutionLocation}/d/tsconfig.json`, content: JSON.stringify({ compilerOptions: { @@ -665,7 +667,7 @@ testCompositeFunction('why hello there', 42);` ] }) }; - const dFile: ts.projectSystem.File = { + const dFile: File = { path: `${solutionLocation}/d/index.ts`, content: ` import { I } from "../a"; @@ -675,32 +677,32 @@ testCompositeFunction('why hello there', 42);` ` }; - const files = [ts.projectSystem.libFile, solutionConfig, aConfig, aFile, bConfig, bFile, cConfig, cFile, dConfig, dFile, ts.projectSystem.libFile]; - const host = ts.projectSystem.createServerHost(files); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([bFile], session); + const files = [libFile, solutionConfig, aConfig, aFile, bConfig, bFile, cConfig, cFile, dConfig, dFile, libFile]; + const host = createServerHost(files); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([bFile], session); // The first search will trigger project loads - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.References, - arguments: ts.projectSystem.protocolFileLocationFromSubstring(bFile, "I", { index: 1 }) + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.References, + arguments: protocolFileLocationFromSubstring(bFile, "I", { index: 1 }) }); // The second search starts with the projects already loaded // Formerly, this would search some projects multiple times - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.References, - arguments: ts.projectSystem.protocolFileLocationFromSubstring(bFile, "I", { index: 1 }) + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.References, + arguments: protocolFileLocationFromSubstring(bFile, "I", { index: 1 }) }); - ts.projectSystem.baselineTsserverLogs("projectReferences", `finding references in overlapping projects`, session); + baselineTsserverLogs("projectReferences", `finding references in overlapping projects`, session); }); describe("special handling of localness of the definitions for findAllRefs", () => { function verify(scenario: string, definition: string, usage: string, referenceTerm: string) { it(scenario, () => { const solutionLocation = "/user/username/projects/solution"; - const solution: ts.projectSystem.File = { + const solution: File = { path: `${solutionLocation}/tsconfig.json`, content: JSON.stringify({ files: [], @@ -710,7 +712,7 @@ testCompositeFunction('why hello there', 42);` ] }) }; - const apiConfig: ts.projectSystem.File = { + const apiConfig: File = { path: `${solutionLocation}/api/tsconfig.json`, content: JSON.stringify({ compilerOptions: { @@ -722,20 +724,20 @@ testCompositeFunction('why hello there', 42);` references: [{ path: "../shared" }] }) }; - const apiFile: ts.projectSystem.File = { + const apiFile: File = { path: `${solutionLocation}/api/src/server.ts`, content: `import * as shared from "../../shared/dist"; ${usage}` }; - const appConfig: ts.projectSystem.File = { + const appConfig: File = { path: `${solutionLocation}/app/tsconfig.json`, content: apiConfig.content }; - const appFile: ts.projectSystem.File = { + const appFile: File = { path: `${solutionLocation}/app/src/app.ts`, content: apiFile.content }; - const sharedConfig: ts.projectSystem.File = { + const sharedConfig: File = { path: `${solutionLocation}/shared/tsconfig.json`, content: JSON.stringify({ compilerOptions: { @@ -746,21 +748,21 @@ ${usage}` include: ["src"] }) }; - const sharedFile: ts.projectSystem.File = { + const sharedFile: File = { path: `${solutionLocation}/shared/src/index.ts`, content: definition }; - const host = ts.projectSystem.createServerHost([ts.projectSystem.libFile, solution, ts.projectSystem.libFile, apiConfig, apiFile, appConfig, appFile, sharedConfig, sharedFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([apiFile], session); + const host = createServerHost([libFile, solution, libFile, apiConfig, apiFile, appConfig, appFile, sharedConfig, sharedFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([apiFile], session); // Find all references - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.References, - arguments: ts.projectSystem.protocolFileLocationFromSubstring(apiFile, referenceTerm) + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.References, + arguments: protocolFileLocationFromSubstring(apiFile, referenceTerm) }); - ts.projectSystem.baselineTsserverLogs("projectReferences", `special handling of localness ${scenario}`, session); + baselineTsserverLogs("projectReferences", `special handling of localness ${scenario}`, session); }); } @@ -806,7 +808,7 @@ export const foo = local;`, it("when disableSolutionSearching is true, solution and siblings are not loaded", () => { const solutionLocation = "/user/username/projects/solution"; - const solution: ts.projectSystem.File = { + const solution: File = { path: `${solutionLocation}/tsconfig.json`, content: JSON.stringify({ files: [], @@ -817,7 +819,7 @@ export const foo = local;`, ] }) }; - const compilerConfig: ts.projectSystem.File = { + const compilerConfig: File = { path: `${solutionLocation}/compiler/tsconfig.json`, content: JSON.stringify({ compilerOptions: { @@ -828,7 +830,7 @@ export const foo = local;`, files: ["./types.ts", "./program.ts"] }) }; - const typesFile: ts.projectSystem.File = { + const typesFile: File = { path: `${solutionLocation}/compiler/types.ts`, content: ` namespace ts { @@ -837,7 +839,7 @@ export const foo = local;`, } }` }; - const programFile: ts.projectSystem.File = { + const programFile: File = { path: `${solutionLocation}/compiler/program.ts`, content: ` namespace ts { @@ -847,7 +849,7 @@ export const foo = local;`, function getSourceFile() { return "something"; } }` }; - const servicesConfig: ts.projectSystem.File = { + const servicesConfig: File = { path: `${solutionLocation}/services/tsconfig.json`, content: JSON.stringify({ compilerOptions: { @@ -859,7 +861,7 @@ export const foo = local;`, ] }) }; - const servicesFile: ts.projectSystem.File = { + const servicesFile: File = { path: `${solutionLocation}/services/services.ts`, content: ` namespace ts { @@ -867,18 +869,18 @@ export const foo = local;`, }` }; - const files = [ts.projectSystem.libFile, solution, compilerConfig, typesFile, programFile, servicesConfig, servicesFile, ts.projectSystem.libFile]; - const host = ts.projectSystem.createServerHost(files); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([programFile], session); + const files = [libFile, solution, compilerConfig, typesFile, programFile, servicesConfig, servicesFile, libFile]; + const host = createServerHost(files); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([programFile], session); // Find all references // No new solutions/projects loaded - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.References, - arguments: ts.projectSystem.protocolFileLocationFromSubstring(programFile, "getSourceFiles") + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.References, + arguments: protocolFileLocationFromSubstring(programFile, "getSourceFiles") }); - ts.projectSystem.baselineTsserverLogs("projectReferences", `with disableSolutionSearching solution and siblings are not loaded`, session); + baselineTsserverLogs("projectReferences", `with disableSolutionSearching solution and siblings are not loaded`, session); }); describe("when default project is solution project", () => { @@ -887,55 +889,55 @@ export const foo = local;`, solutionOptions?: ts.CompilerOptions; solutionFiles?: string[]; configRefs: string[]; - additionalFiles: readonly ts.projectSystem.File[]; + additionalFiles: readonly File[]; } - const main: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/src/main.ts`, + const main: File = { + path: `/user/username/projects/myproject/src/main.ts`, content: `import { foo } from 'helpers/functions'; export { foo };` }; - const helper: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/src/helpers/functions.ts`, + const helper: File = { + path: `/user/username/projects/myproject/src/helpers/functions.ts`, content: `export const foo = 1;` }; - const mainDts: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/target/src/main.d.ts`, + const mainDts: File = { + path: `/user/username/projects/myproject/target/src/main.d.ts`, content: `import { foo } from 'helpers/functions'; export { foo }; //# sourceMappingURL=main.d.ts.map` }; - const mainDtsMap: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/target/src/main.d.ts.map`, + const mainDtsMap: File = { + path: `/user/username/projects/myproject/target/src/main.d.ts.map`, content: `{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAExC,OAAO,EAAC,GAAG,EAAC,CAAC"}` }; - const helperDts: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/target/src/helpers/functions.d.ts`, + const helperDts: File = { + path: `/user/username/projects/myproject/target/src/helpers/functions.d.ts`, content: `export declare const foo = 1; //# sourceMappingURL=functions.d.ts.map` }; - const helperDtsMap: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/target/src/helpers/functions.d.ts.map`, + const helperDtsMap: File = { + path: `/user/username/projects/myproject/target/src/helpers/functions.d.ts.map`, content: `{"version":3,"file":"functions.d.ts","sourceRoot":"","sources":["../../../src/helpers/functions.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,GAAG,IAAI,CAAC"}` }; - const tsconfigIndirect3: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/indirect3/tsconfig.json`, + const tsconfigIndirect3: File = { + path: `/user/username/projects/myproject/indirect3/tsconfig.json`, content: JSON.stringify({ compilerOptions: { baseUrl: "../target/src/" }, }) }; - const fileResolvingToMainDts: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/indirect3/main.ts`, + const fileResolvingToMainDts: File = { + path: `/user/username/projects/myproject/indirect3/main.ts`, content: `import { foo } from 'main'; foo; export function bar() {}` }; - const tsconfigSrcPath = `${ts.tscWatch.projectRoot}/tsconfig-src.json`; - const tsconfigPath = `${ts.tscWatch.projectRoot}/tsconfig.json`; + const tsconfigSrcPath = `/user/username/projects/myproject/tsconfig-src.json`; + const tsconfigPath = `/user/username/projects/myproject/tsconfig.json`; const dummyFilePath = "/dummy/dummy.ts"; function setup({ solutionFiles, solutionOptions, configRefs, additionalFiles }: Setup) { - const tsconfigSrc: ts.projectSystem.File = { + const tsconfigSrc: File = { path: tsconfigSrcPath, content: JSON.stringify({ compilerOptions: { @@ -946,7 +948,7 @@ export function bar() {}` include: ["./src/**/*"] }) }; - const tsconfig: ts.projectSystem.File = { + const tsconfig: File = { path: tsconfigPath, content: JSON.stringify({ ... (solutionOptions ? { compilerOptions: solutionOptions } : {}), @@ -954,17 +956,17 @@ export function bar() {}` files: solutionFiles || [] }) }; - const dummyFile: ts.projectSystem.File = { + const dummyFile: File = { path: dummyFilePath, content: "let a = 10;" }; - const host = ts.projectSystem.createServerHost([ + const host = createServerHost([ tsconfigSrc, tsconfig, main, helper, - ts.projectSystem.libFile, dummyFile, + libFile, dummyFile, mainDts, mainDtsMap, helperDts, helperDtsMap, tsconfigIndirect3, fileResolvingToMainDts, ...additionalFiles]); - const session = ts.projectSystem.createSession(host, { canUseEvents: true, logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); + const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); const service = session.getProjectService(); service.openClientFile(main.path); return { session, service, host }; @@ -980,7 +982,7 @@ export function bar() {}` session.logger.endGroup(); // Verify errors - ts.projectSystem.verifyGetErrRequest({ session, host, files: [main] }); + verifyGetErrRequest({ session, host, files: [main] }); // Verify collection of script infos service.openClientFile(dummyFilePath); @@ -997,10 +999,10 @@ export function bar() {}` service.reloadProjects(); // Find all refs - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.References, - arguments: ts.projectSystem.protocolFileLocationFromSubstring(main, "foo", { index: 1 }) - }).response as ts.projectSystem.protocol.ReferencesResponseBody; + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.References, + arguments: protocolFileLocationFromSubstring(main, "foo", { index: 1 }) + }).response as ts.server.protocol.ReferencesResponseBody; service.closeClientFile(main.path); service.closeClientFile(dummyFilePath); @@ -1009,16 +1011,16 @@ export function bar() {}` service.openClientFile(fileResolvingToMainDts.path); // Find all refs from dts include - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.References, - arguments: ts.projectSystem.protocolFileLocationFromSubstring(fileResolvingToMainDts, "foo") - }).response as ts.projectSystem.protocol.ReferencesResponseBody; - ts.projectSystem.baselineTsserverLogs("projectReferences", input.scenario, session); + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.References, + arguments: protocolFileLocationFromSubstring(fileResolvingToMainDts, "foo") + }).response as ts.server.protocol.ReferencesResponseBody; + baselineTsserverLogs("projectReferences", input.scenario, session); } function getIndirectProject(postfix: string, optionsToExtend?: ts.CompilerOptions) { - const tsconfigIndirect: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/tsconfig-indirect${postfix}.json`, + const tsconfigIndirect: File = { + path: `/user/username/projects/myproject/tsconfig-indirect${postfix}.json`, content: JSON.stringify({ compilerOptions: { composite: true, @@ -1030,8 +1032,8 @@ export function bar() {}` references: [{ path: "./tsconfig-src.json" }] }) }; - const indirect: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/indirect${postfix}/main.ts`, + const indirect: File = { + path: `/user/username/projects/myproject/indirect${postfix}/main.ts`, content: fileResolvingToMainDts.content }; return { tsconfigIndirect, indirect }; @@ -1057,7 +1059,7 @@ export function bar() {}` // Verify Reload projects service.reloadProjects(); - ts.projectSystem.baselineTsserverLogs("projectReferences", input.scenario, session); + baselineTsserverLogs("projectReferences", input.scenario, session); } it("when project is directly referenced by solution", () => { @@ -1108,8 +1110,8 @@ export function bar() {}` describe("when solution is project that contains its own files", () => { it("when the project found is not solution but references open file through project reference", () => { - const ownMain: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/own/main.ts`, + const ownMain: File = { + path: `/user/username/projects/myproject/own/main.ts`, content: fileResolvingToMainDts.content }; verifySolutionScenario({ @@ -1125,8 +1127,8 @@ export function bar() {}` }); it("when project is indirectly referenced by solution", () => { - const ownMain: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/own/main.ts`, + const ownMain: File = { + path: `/user/username/projects/myproject/own/main.ts`, content: `import { bar } from 'main'; bar;` }; @@ -1145,8 +1147,8 @@ bar;` }); it("disables looking into the child project if disableReferencedProjectLoad is set", () => { - const ownMain: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/own/main.ts`, + const ownMain: File = { + path: `/user/username/projects/myproject/own/main.ts`, content: fileResolvingToMainDts.content }; verifyDisableReferencedProjectLoad({ @@ -1163,8 +1165,8 @@ bar;` }); it("disables looking into the child project if disableReferencedProjectLoad is set in indirect project", () => { - const ownMain: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/own/main.ts`, + const ownMain: File = { + path: `/user/username/projects/myproject/own/main.ts`, content: `import { bar } from 'main'; bar;` }; @@ -1182,8 +1184,8 @@ bar;` }); it("disables looking into the child project if disableReferencedProjectLoad is set in first indirect project but not in another one", () => { - const ownMain: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/own/main.ts`, + const ownMain: File = { + path: `/user/username/projects/myproject/own/main.ts`, content: `import { bar } from 'main'; bar;` }; @@ -1205,8 +1207,8 @@ bar;` describe("when new file is added to the referenced project", () => { function setup(extendOptionsProject2?: ts.CompilerOptions) { - const config1: ts.projectSystem.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", @@ -1215,16 +1217,16 @@ bar;` exclude: ["temp"] }) }; - const class1: ts.projectSystem.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.projectSystem.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.projectSystem.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", @@ -1236,13 +1238,13 @@ bar;` ] }) }; - const class2: ts.projectSystem.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 host = ts.projectSystem.createServerHost([config1, class1, class1Dts, config2, class2, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([class2], session); + const host = createServerHost([config1, class1, class1Dts, config2, class2, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([class2], session); return { host, session, class1 }; } @@ -1250,52 +1252,52 @@ bar;` const { host, session } = setup(); // Add new class to referenced project - const class3 = `${ts.tscWatch.projectRoot}/projects/project1/class3.ts`; + const class3 = `/user/username/projects/myproject/projects/project1/class3.ts`; host.writeFile(class3, `class class3 {}`); host.checkTimeoutQueueLengthAndRun(2); // Add excluded file to referenced project - host.ensureFileOrFolder({ path: `${ts.tscWatch.projectRoot}/projects/project1/temp/file.d.ts`, content: `declare class file {}` }); + host.ensureFileOrFolder({ path: `/user/username/projects/myproject/projects/project1/temp/file.d.ts`, content: `declare class file {}` }); host.checkTimeoutQueueLengthAndRun(0); // Add output from new class to referenced project - const class3Dts = `${ts.tscWatch.projectRoot}/projects/project1/class3.d.ts`; + const class3Dts = `/user/username/projects/myproject/projects/project1/class3.d.ts`; host.writeFile(class3Dts, `declare class class3 {}`); host.checkTimeoutQueueLengthAndRun(0); - ts.projectSystem.baselineTsserverLogs("projectReferences", `new file is added to the referenced project when referenced project is not open`, session); + baselineTsserverLogs("projectReferences", `new file is added to the referenced project when referenced project is not open`, session); }); it("when referenced project is open", () => { const { host, session, class1 } = setup(); - ts.projectSystem.openFilesForSession([class1], session); + openFilesForSession([class1], session); // Add new class to referenced project - const class3 = `${ts.tscWatch.projectRoot}/projects/project1/class3.ts`; + const class3 = `/user/username/projects/myproject/projects/project1/class3.ts`; host.writeFile(class3, `class class3 {}`); host.checkTimeoutQueueLengthAndRun(3); // Add excluded file to referenced project - host.ensureFileOrFolder({ path: `${ts.tscWatch.projectRoot}/projects/project1/temp/file.d.ts`, content: `declare class file {}` }); + host.ensureFileOrFolder({ path: `/user/username/projects/myproject/projects/project1/temp/file.d.ts`, content: `declare class file {}` }); host.checkTimeoutQueueLengthAndRun(0); // Add output from new class to referenced project - const class3Dts = `${ts.tscWatch.projectRoot}/projects/project1/class3.d.ts`; + const class3Dts = `/user/username/projects/myproject/projects/project1/class3.d.ts`; host.writeFile(class3Dts, `declare class class3 {}`); host.checkTimeoutQueueLengthAndRun(0); - ts.projectSystem.baselineTsserverLogs("projectReferences", `new file is added to the referenced project when referenced project is open`, session); + baselineTsserverLogs("projectReferences", `new file is added to the referenced project when referenced project is open`, session); }); it("when referenced project is not open with disableSourceOfProjectReferenceRedirect", () => { const { host, session } = setup({ disableSourceOfProjectReferenceRedirect: true }); // Add new class to referenced project - const class3 = `${ts.tscWatch.projectRoot}/projects/project1/class3.ts`; + const class3 = `/user/username/projects/myproject/projects/project1/class3.ts`; host.writeFile(class3, `class class3 {}`); host.checkTimeoutQueueLengthAndRun(2); // Add output of new class to referenced project - const class3Dts = `${ts.tscWatch.projectRoot}/projects/project1/class3.d.ts`; + const class3Dts = `/user/username/projects/myproject/projects/project1/class3.d.ts`; host.writeFile(class3Dts, `declare class class3 {}`); host.checkTimeoutQueueLengthAndRun(2); // Add excluded file to referenced project - host.ensureFileOrFolder({ path: `${ts.tscWatch.projectRoot}/projects/project1/temp/file.d.ts`, content: `declare class file {}` }); + host.ensureFileOrFolder({ path: `/user/username/projects/myproject/projects/project1/temp/file.d.ts`, content: `declare class file {}` }); host.checkTimeoutQueueLengthAndRun(0); // Delete output from new class to referenced project host.deleteFile(class3Dts); @@ -1303,23 +1305,23 @@ bar;` // Write back output of new class to referenced project host.writeFile(class3Dts, `declare class class3 {}`); host.checkTimeoutQueueLengthAndRun(2); - ts.projectSystem.baselineTsserverLogs("projectReferences", `new file is added to the referenced project when referenced project is not open with disableSourceOfProjectReferenceRedirect`, session); + baselineTsserverLogs("projectReferences", `new file is added to the referenced project when referenced project is not open with disableSourceOfProjectReferenceRedirect`, session); }); it("when referenced project is open with disableSourceOfProjectReferenceRedirect", () => { const { host, session, class1 } = setup({ disableSourceOfProjectReferenceRedirect: true }); - ts.projectSystem.openFilesForSession([class1], session); + openFilesForSession([class1], session); // Add new class to referenced project - const class3 = `${ts.tscWatch.projectRoot}/projects/project1/class3.ts`; + const class3 = `/user/username/projects/myproject/projects/project1/class3.ts`; host.writeFile(class3, `class class3 {}`); host.checkTimeoutQueueLengthAndRun(3); // Add output of new class to referenced project - const class3Dts = `${ts.tscWatch.projectRoot}/projects/project1/class3.d.ts`; + const class3Dts = `/user/username/projects/myproject/projects/project1/class3.d.ts`; host.writeFile(class3Dts, `declare class class3 {}`); host.checkTimeoutQueueLengthAndRun(2); // Add excluded file to referenced project - host.ensureFileOrFolder({ path: `${ts.tscWatch.projectRoot}/projects/project1/temp/file.d.ts`, content: `declare class file {}` }); + host.ensureFileOrFolder({ path: `/user/username/projects/myproject/projects/project1/temp/file.d.ts`, content: `declare class file {}` }); host.checkTimeoutQueueLengthAndRun(0); // Delete output from new class to referenced project host.deleteFile(class3Dts); @@ -1327,14 +1329,14 @@ bar;` // Write back output of new class to referenced project host.writeFile(class3Dts, `declare class class3 {}`); host.checkTimeoutQueueLengthAndRun(2); - ts.projectSystem.baselineTsserverLogs("projectReferences", `new file is added to the referenced project when referenced project is open with disableSourceOfProjectReferenceRedirect`, session); + baselineTsserverLogs("projectReferences", `new file is added to the referenced project when referenced project is open with disableSourceOfProjectReferenceRedirect`, session); }); }); describe("auto import with referenced project", () => { function verifyAutoImport(built: boolean, disableSourceOfProjectReferenceRedirect?: boolean) { - const solnConfig: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/tsconfig.json`, + const solnConfig: File = { + path: `/user/username/projects/myproject/tsconfig.json`, content: JSON.stringify({ files: [], references: [ @@ -1343,8 +1345,8 @@ bar;` ] }) }; - const sharedConfig: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/shared/src/library/tsconfig.json`, + const sharedConfig: File = { + path: `/user/username/projects/myproject/shared/src/library/tsconfig.json`, content: JSON.stringify({ compilerOptions: { composite: true, @@ -1352,12 +1354,12 @@ bar;` } }) }; - const sharedIndex: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/shared/src/library/index.ts`, + const sharedIndex: File = { + path: `/user/username/projects/myproject/shared/src/library/index.ts`, content: `export function foo() {}` }; - const sharedPackage: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/shared/package.json`, + const sharedPackage: File = { + path: `/user/username/projects/myproject/shared/package.json`, content: JSON.stringify({ name: "shared", version: "1.0.0", @@ -1365,8 +1367,8 @@ bar;` types: "bld/library/index.d.ts" }) }; - const appConfig: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/app/src/program/tsconfig.json`, + const appConfig: File = { + path: `/user/username/projects/myproject/app/src/program/tsconfig.json`, content: JSON.stringify({ compilerOptions: { composite: true, @@ -1378,28 +1380,28 @@ bar;` ] }) }; - const appBar: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/app/src/program/bar.ts`, + const appBar: File = { + path: `/user/username/projects/myproject/app/src/program/bar.ts`, content: `import {foo} from "shared";` }; - const appIndex: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/app/src/program/index.ts`, + const appIndex: File = { + path: `/user/username/projects/myproject/app/src/program/index.ts`, content: `foo` }; - const sharedSymlink: ts.projectSystem.SymLink = { - path: `${ts.tscWatch.projectRoot}/node_modules/shared`, - symLink: `${ts.tscWatch.projectRoot}/shared` + const sharedSymlink: SymLink = { + path: `/user/username/projects/myproject/node_modules/shared`, + symLink: `/user/username/projects/myproject/shared` }; - const files = [solnConfig, sharedConfig, sharedIndex, sharedPackage, appConfig, appBar, appIndex, sharedSymlink, ts.projectSystem.libFile]; - const host = ts.projectSystem.createServerHost(files); + const files = [solnConfig, sharedConfig, sharedIndex, sharedPackage, appConfig, appBar, appIndex, sharedSymlink, libFile]; + const host = createServerHost(files); if (built) { - ts.tscWatch.solutionBuildWithBaseline(host, [solnConfig.path]); + solutionBuildWithBaseline(host, [solnConfig.path]); host.clearOutput(); } - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([appIndex], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.GetCodeFixes, + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([appIndex], session); + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.GetCodeFixes, arguments: { file: appIndex.path, startLine: 1, @@ -1409,7 +1411,7 @@ bar;` errorCodes: [ts.Diagnostics.Cannot_find_name_0.code], } }); - ts.projectSystem.baselineTsserverLogs("projectReferences", `auto import with referenced project${built ? " when built" : ""}${disableSourceOfProjectReferenceRedirect ? " with disableSourceOfProjectReferenceRedirect": ""}`, session); + baselineTsserverLogs("projectReferences", `auto import with referenced project${built ? " when built" : ""}${disableSourceOfProjectReferenceRedirect ? " with disableSourceOfProjectReferenceRedirect": ""}`, session); } it("when project is built", () => { @@ -1424,13 +1426,13 @@ bar;` }); it("when files from two projects are open and one project references", () => { - function getPackageAndFile(packageName: string, references?: string[], optionsToExtend?: ts.CompilerOptions): [file: ts.projectSystem.File, config: ts.projectSystem.File] { - const file: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/${packageName}/src/file1.ts`, + function getPackageAndFile(packageName: string, references?: string[], optionsToExtend?: ts.CompilerOptions): [file: File, config: File] { + const file: File = { + path: `/user/username/projects/myproject/${packageName}/src/file1.ts`, content: `export const ${packageName}Const = 10;` }; - const config: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/${packageName}/tsconfig.json`, + const config: File = { + path: `/user/username/projects/myproject/${packageName}/tsconfig.json`, content: JSON.stringify({ compilerOptions: { composite: true, ...optionsToExtend || {} }, references: references?.map(path => ({ path: `../${path}` })) @@ -1451,35 +1453,35 @@ bar;` const [indirectNoCoreRefFile, indirectNoCoreRefConfig] = getPackageAndFile("indirectNoCoreRef", ["noCoreRef2"]); const [noCoreRef2File, noCoreRef2Config] = getPackageAndFile("noCoreRef2"); - const host = ts.projectSystem.createServerHost([ - ts.projectSystem.libFile, mainFile, mainConfig, coreFile, coreConfig, noCoreRef1File, noCoreRef1Config, + const host = createServerHost([ + libFile, mainFile, mainConfig, coreFile, coreConfig, noCoreRef1File, noCoreRef1Config, indirectFile, indirectConfig, coreRef1File, coreRef1Config, indirectDisabledChildLoad1File, indirectDisabledChildLoad1Config, coreRef2File, coreRef2Config, indirectDisabledChildLoad2File, indirectDisabledChildLoad2Config, coreRef3File, coreRef3Config, refToCoreRef3File, refToCoreRef3Config, indirectNoCoreRefFile, indirectNoCoreRefConfig, noCoreRef2File, noCoreRef2Config ], { useCaseSensitiveFileNames: true }); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([mainFile, coreFile], session); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([mainFile, coreFile], session); // Find all refs in coreFile - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.References, - arguments: ts.projectSystem.protocolFileLocationFromSubstring(coreFile, `coreConst`) + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.References, + arguments: protocolFileLocationFromSubstring(coreFile, `coreConst`) }); - ts.projectSystem.baselineTsserverLogs("projectReferences", `when files from two projects are open and one project references`, session); + baselineTsserverLogs("projectReferences", `when files from two projects are open and one project references`, session); }); describe("find refs to decl in other proj", () => { - const indexA: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/a/index.ts`, + const indexA: File = { + path: `/user/username/projects/myproject/a/index.ts`, content: `import { B } from "../b/lib"; const b: B = new B();` }; - const configB: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/b/tsconfig.json`, + const configB: File = { + path: `/user/username/projects/myproject/b/tsconfig.json`, content: `{ "compilerOptions": { "declarationMap": true, @@ -1489,30 +1491,30 @@ const b: B = new B();` }` }; - const indexB: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/b/index.ts`, + const indexB: File = { + path: `/user/username/projects/myproject/b/index.ts`, content: `export class B { M() {} }` }; - const helperB: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/b/helper.ts`, + const helperB: File = { + path: `/user/username/projects/myproject/b/helper.ts`, content: `import { B } from "."; const b: B = new B();` }; - const dtsB: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/b/lib/index.d.ts`, + const dtsB: File = { + path: `/user/username/projects/myproject/b/lib/index.d.ts`, content: `export declare class B { M(): void; } //# sourceMappingURL=index.d.ts.map` }; - const dtsMapB: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/b/lib/index.d.ts.map`, + const dtsMapB: File = { + path: `/user/username/projects/myproject/b/lib/index.d.ts.map`, content: `{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,qBAAa,CAAC;IACV,CAAC;CACJ"}` }; @@ -1535,23 +1537,23 @@ const b: B = new B();` }; it(subScenario, () => { - const configA: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/a/tsconfig.json`, + const configA: File = { + path: `/user/username/projects/myproject/a/tsconfig.json`, content: `{ "compilerOptions": ${JSON.stringify(compilerOptions)}, "references": [{ "path": "../b" }] }` }; - const host = ts.projectSystem.createServerHost([configA, indexA, configB, indexB, helperB, dtsB, ...(dtsMapPresent ? [dtsMapB] : [])]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([indexA, ...(projectAlreadyLoaded ? [helperB] : [])], session); + const host = createServerHost([configA, indexA, configB, indexB, helperB, dtsB, ...(dtsMapPresent ? [dtsMapB] : [])]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([indexA, ...(projectAlreadyLoaded ? [helperB] : [])], session); - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.References, - arguments: ts.projectSystem.protocolFileLocationFromSubstring(indexA, `B`, { index: 1 }) + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.References, + arguments: protocolFileLocationFromSubstring(indexA, `B`, { index: 1 }) }); - ts.projectSystem.baselineTsserverLogs("projectReferences", `find refs to decl in other proj ${subScenario}`, session); + baselineTsserverLogs("projectReferences", `find refs to decl in other proj ${subScenario}`, session); }); } diff --git a/src/testRunner/unittests/tsserver/projectReferencesSourcemap.ts b/src/testRunner/unittests/tsserver/projectReferencesSourcemap.ts index fd644f62916..e8149dae664 100644 --- a/src/testRunner/unittests/tsserver/projectReferencesSourcemap.ts +++ b/src/testRunner/unittests/tsserver/projectReferencesSourcemap.ts @@ -1,10 +1,12 @@ import * as ts from "../../_namespaces/ts"; +import { createServerHost, File, libFile, TestServerHost } from "../virtualFileSystemWithWatch"; +import { TestSession, closeFilesForSession, openFilesForSession, createHostWithSolutionBuild, createSession, createLoggerWithInMemoryLogs, baselineTsserverLogs } from "./helpers"; describe("unittests:: tsserver:: with project references and tsbuild source map", () => { - const dependecyLocation = `${ts.tscWatch.projectRoot}/dependency`; - const dependecyDeclsLocation = `${ts.tscWatch.projectRoot}/decls`; - const mainLocation = `${ts.tscWatch.projectRoot}/main`; - const dependencyTs: ts.projectSystem.File = { + const dependecyLocation = `/user/username/projects/myproject/dependency`; + const dependecyDeclsLocation = `/user/username/projects/myproject/decls`; + const mainLocation = `/user/username/projects/myproject/main`; + const dependencyTs: File = { path: `${dependecyLocation}/FnS.ts`, content: `export function fn1() { } export function fn2() { } @@ -13,12 +15,12 @@ export function fn4() { } export function fn5() { } ` }; - const dependencyConfig: ts.projectSystem.File = { + const dependencyConfig: File = { path: `${dependecyLocation}/tsconfig.json`, content: JSON.stringify({ compilerOptions: { composite: true, declarationMap: true, declarationDir: "../decls" } }) }; - const mainTs: ts.projectSystem.File = { + const mainTs: File = { path: `${mainLocation}/main.ts`, content: `import { fn1, @@ -35,7 +37,7 @@ fn4(); fn5(); ` }; - const mainConfig: ts.projectSystem.File = { + const mainConfig: File = { path: `${mainLocation}/tsconfig.json`, content: JSON.stringify({ compilerOptions: { composite: true, declarationMap: true }, @@ -43,12 +45,12 @@ fn5(); }) }; - const randomFile: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/random/random.ts`, + const randomFile: File = { + path: `/user/username/projects/myproject/random/random.ts`, content: "let a = 10;" }; - const randomConfig: ts.projectSystem.File = { - path: `${ts.tscWatch.projectRoot}/random/tsconfig.json`, + const randomConfig: File = { + path: `/user/username/projects/myproject/random/tsconfig.json`, content: "{}" }; const dtsLocation = `${dependecyDeclsLocation}/FnS.d.ts`; @@ -56,9 +58,9 @@ fn5(); const dtsMapLocation = `${dependecyDeclsLocation}/FnS.d.ts.map`; const dtsMapPath = dtsMapLocation.toLowerCase() as ts.Path; - const files = [dependencyTs, dependencyConfig, mainTs, mainConfig, ts.projectSystem.libFile, randomFile, randomConfig]; + const files = [dependencyTs, dependencyConfig, mainTs, mainConfig, libFile, randomFile, randomConfig]; - function changeDtsFile(host: ts.projectSystem.TestServerHost) { + function changeDtsFile(host: TestServerHost) { host.writeFile( dtsLocation, host.readFile(dtsLocation)!.replace( @@ -69,23 +71,23 @@ fn5(); ); } - function changeDtsMapFile(host: ts.projectSystem.TestServerHost) { + function changeDtsMapFile(host: TestServerHost) { host.writeFile( dtsMapLocation, `{"version":3,"file":"FnS.d.ts","sourceRoot":"","sources":["../dependency/FnS.ts"],"names":[],"mappings":"AAAA,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,eAAO,MAAM,CAAC,KAAK,CAAC"}` ); } - function goToDefFromMainTs(fn: number): Partial { + function goToDefFromMainTs(fn: number): Partial { return { - command: ts.projectSystem.protocol.CommandTypes.DefinitionAndBoundSpan, + command: ts.server.protocol.CommandTypes.DefinitionAndBoundSpan, arguments: { file: mainTs.path, line: fn + 8, offset: 1 } }; } - function renameFromDependencyTs(fn: number): Partial { + function renameFromDependencyTs(fn: number): Partial { return { - command: ts.projectSystem.protocol.CommandTypes.Rename, + command: ts.server.protocol.CommandTypes.Rename, arguments: { file: dependencyTs.path, line: fn, offset: 17 } }; } @@ -95,7 +97,7 @@ fn5(); } function verifyDocumentPositionMapper( - session: ts.projectSystem.TestSession, + session: TestSession, dependencyMap: ts.server.ScriptInfo | undefined, documentPositionMapper: ts.server.ScriptInfo["documentPositionMapper"], equal: boolean, @@ -108,7 +110,7 @@ fn5(); } function verifyDocumentPositionMapperEqual( - session: ts.projectSystem.TestSession, + session: TestSession, dependencyMap: ts.server.ScriptInfo | undefined, documentPositionMapper: ts.server.ScriptInfo["documentPositionMapper"], debugInfo?: string, @@ -125,8 +127,8 @@ fn5(); } } - function verifyAllFnAction( - session: ts.projectSystem.TestSession, + function verifyAllFnAction( + session: TestSession, action: (fn: number) => Partial, existingDependencyMap: ts.server.ScriptInfo | undefined, existingDocumentPositionMapper: ts.server.ScriptInfo["documentPositionMapper"], @@ -171,14 +173,14 @@ fn5(); } function verifyScriptInfoCollectionWith( - session: ts.projectSystem.TestSession, - openFiles: readonly ts.projectSystem.File[], + session: TestSession, + openFiles: readonly File[], ) { const { dependencyMap, documentPositionMapper } = getDocumentPositionMapper(session); // Collecting at this point retains dependency.d.ts and map - ts.projectSystem.closeFilesForSession([randomFile], session); - ts.projectSystem.openFilesForSession([randomFile], session); + closeFilesForSession([randomFile], session); + openFilesForSession([randomFile], session); // If map is not collected, document position mapper shouldnt change if (session.getProjectService().filenameToScriptInfo.has(dtsMapPath)) { @@ -186,15 +188,15 @@ fn5(); } // Closing open file, removes dependencies too - ts.projectSystem.closeFilesForSession([...openFiles, randomFile], session); - ts.projectSystem.openFilesForSession([randomFile], session); + closeFilesForSession([...openFiles, randomFile], session); + openFilesForSession([randomFile], session); } - type OnHostCreate = (host: ts.projectSystem.TestServerHost) => void; - type CreateSessionFn = (onHostCreate?: OnHostCreate) => { host: ts.projectSystem.TestServerHost; session: ts.projectSystem.TestSession; }; - function setupWith(createSession: CreateSessionFn, openFiles: readonly ts.projectSystem.File[], onHostCreate: OnHostCreate | undefined) { + type OnHostCreate = (host: TestServerHost) => void; + type CreateSessionFn = (onHostCreate?: OnHostCreate) => { host: TestServerHost; session: TestSession; }; + function setupWith(createSession: CreateSessionFn, openFiles: readonly File[], onHostCreate: OnHostCreate | undefined) { const result = createSession(onHostCreate); - ts.projectSystem.openFilesForSession(openFiles, result.session); + openFilesForSession(openFiles, result.session); return result; } @@ -211,25 +213,25 @@ fn5(); } function createSessionWithoutProjectReferences(onHostCreate?: OnHostCreate) { - const host = ts.projectSystem.createHostWithSolutionBuild(files, [mainConfig.path]); + const host = createHostWithSolutionBuild(files, [mainConfig.path]); // Erase project reference host.writeFile(mainConfig.path, JSON.stringify({ compilerOptions: { composite: true, declarationMap: true } })); onHostCreate?.(host); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); return { host, session }; } function createSessionWithProjectReferences(onHostCreate?: OnHostCreate) { - const host = ts.projectSystem.createHostWithSolutionBuild(files, [mainConfig.path]); + const host = createHostWithSolutionBuild(files, [mainConfig.path]); onHostCreate?.(host); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); return { host, session }; } function createSessionWithDisabledProjectReferences(onHostCreate?: OnHostCreate) { - const host = ts.projectSystem.createHostWithSolutionBuild(files, [mainConfig.path]); + const host = createHostWithSolutionBuild(files, [mainConfig.path]); // Erase project reference host.writeFile(mainConfig.path, JSON.stringify({ compilerOptions: { @@ -240,19 +242,19 @@ fn5(); references: [{ path: "../dependency" }] })); onHostCreate?.(host); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); return { host, session }; } - function getDocumentPositionMapper(session: ts.projectSystem.TestSession) { + function getDocumentPositionMapper(session: TestSession) { const dependencyMap = session.getProjectService().filenameToScriptInfo.get(dtsMapPath); const documentPositionMapper = dependencyMap?.documentPositionMapper; return { dependencyMap, documentPositionMapper }; } - function makeChangeToMainTs(session: ts.projectSystem.TestSession) { - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + function makeChangeToMainTs(session: TestSession) { + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: mainTs.path, line: 14, @@ -264,9 +266,9 @@ fn5(); }); } - function makeChangeToDependencyTs(session: ts.projectSystem.TestSession) { - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + function makeChangeToDependencyTs(session: TestSession) { + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: dependencyTs.path, line: 6, @@ -306,7 +308,7 @@ fn5(); /*existingDocumentPositionMapperEqual*/ false ); verifyScriptInfoCollectionWith(session, [mainTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/can go to definition correctly", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/can go to definition correctly", session); }); // Edit @@ -328,7 +330,7 @@ fn5(); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/usage file changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/usage file changes with timeout before request", session); }); it(`when usage file changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -346,7 +348,7 @@ fn5(); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/usage file changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/usage file changes", session); }); // Edit dts to add new fn @@ -368,7 +370,7 @@ fn5(); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dts changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dts changes with timeout before request", session); }); it(`when dependency .d.ts changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -386,7 +388,7 @@ fn5(); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dts changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dts changes", session); }); // Edit map file to represent added new line @@ -408,7 +410,7 @@ fn5(); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ false ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dtsMap changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dtsMap changes with timeout before request", session); }); it(`when dependency file's map changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -426,7 +428,7 @@ fn5(); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ false ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dtsMap changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dtsMap changes", session); }); it(`with depedency files map file, when file is not present`, () => { @@ -441,7 +443,7 @@ fn5(); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dtsMap not present", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dtsMap not present", session); }); it(`with depedency files map file, when file is created after actions on projects`, () => { let fileContents: string; @@ -460,7 +462,7 @@ fn5(); /*existingDocumentPositionMapperEqual*/ false ); verifyScriptInfoCollectionWith(session, [mainTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dtsMap created", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dtsMap created", session); }); it(`with depedency files map file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -476,7 +478,7 @@ fn5(); /*existingDocumentPositionMapperEqual*/ false ); verifyScriptInfoCollectionWith(session, [mainTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dtsMap deleted", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dtsMap deleted", session); }); it(`with depedency .d.ts file, when file is not present`, () => { @@ -491,7 +493,7 @@ fn5(); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dts not present", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dts not present", session); }); it(`with depedency .d.ts file, when file is created after actions on projects`, () => { let fileContents: string; @@ -510,7 +512,7 @@ fn5(); /*existingDocumentPositionMapperEqual*/ false ); verifyScriptInfoCollectionWith(session, [mainTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dts created", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dts created", session); }); it(`with depedency .d.ts file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -526,7 +528,7 @@ fn5(); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dts deleted", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dts deleted", session); }); }); describe("when main tsconfig has project reference", () => { @@ -549,7 +551,7 @@ fn5(); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/can go to definition correctly", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/can go to definition correctly", session); }); // Edit @@ -571,7 +573,7 @@ fn5(); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/usage file changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/usage file changes with timeout before request", session); }); it(`when usage file changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -589,7 +591,7 @@ fn5(); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/usage file changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/usage file changes", session); }); // Edit dts to add new fn @@ -611,7 +613,7 @@ fn5(); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dts changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dts changes with timeout before request", session); }); it(`when dependency .d.ts changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -629,7 +631,7 @@ fn5(); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dts changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dts changes", session); }); // Edit map file to represent added new line @@ -651,7 +653,7 @@ fn5(); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dtsMap changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dtsMap changes with timeout before request", session); }); it(`when dependency file's map changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -669,7 +671,7 @@ fn5(); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dtsMap changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dtsMap changes", session); }); it(`with depedency files map file, when file is not present`, () => { @@ -684,7 +686,7 @@ fn5(); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dtsMap not present", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dtsMap not present", session); }); it(`with depedency files map file, when file is created after actions on projects`, () => { let fileContents: string; @@ -703,7 +705,7 @@ fn5(); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dtsMap created", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dtsMap created", session); }); it(`with depedency files map file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -719,7 +721,7 @@ fn5(); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dtsMap deleted", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dtsMap deleted", session); }); it(`with depedency .d.ts file, when file is not present`, () => { @@ -734,7 +736,7 @@ fn5(); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dts not present", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dts not present", session); }); it(`with depedency .d.ts file, when file is created after actions on projects`, () => { let fileContents: string; @@ -753,7 +755,7 @@ fn5(); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dts created", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dts created", session); }); it(`with depedency .d.ts file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -769,7 +771,7 @@ fn5(); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dts deleted", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dts deleted", session); }); it(`when defining project source changes, when timeout occurs before request`, () => { // Create DocumentPositionMapper @@ -791,7 +793,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency source changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency source changes with timeout before request", session); }); it(`when defining project source changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -811,13 +813,13 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency source changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency source changes", session); }); it("when projects are not built", () => { - const host = ts.projectSystem.createServerHost(files); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([mainTs, randomFile], session); + const host = createServerHost(files); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([mainTs, randomFile], session); verifyAllFnAction( session, goToDefFromMainTs, @@ -827,7 +829,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/when projects are not built", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/when projects are not built", session); }); }); describe("when main tsconfig has disableSourceOfProjectReferenceRedirect along with project reference", () => { @@ -850,7 +852,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ false ); verifyScriptInfoCollectionWith(session, [mainTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/can go to definition correctly", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/can go to definition correctly", session); }); // Edit @@ -872,7 +874,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/usage file changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/usage file changes with timeout before request", session); }); it(`when usage file changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -890,7 +892,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/usage file changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/usage file changes", session); }); // Edit dts to add new fn @@ -912,7 +914,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dts changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dts changes with timeout before request", session); }); it(`when dependency .d.ts changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -930,7 +932,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dts changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dts changes", session); }); // Edit map file to represent added new line @@ -952,7 +954,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ false ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dtsMap changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dtsMap changes with timeout before request", session); }); it(`when dependency file's map changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -970,7 +972,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ false ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dtsMap changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dtsMap changes", session); }); it(`with depedency files map file, when file is not present`, () => { @@ -985,7 +987,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dtsMap not present", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dtsMap not present", session); }); it(`with depedency files map file, when file is created after actions on projects`, () => { let fileContents: string; @@ -1004,7 +1006,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ false ); verifyScriptInfoCollectionWith(session, [mainTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dtsMap created", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dtsMap created", session); }); it(`with depedency files map file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -1020,7 +1022,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ false ); verifyScriptInfoCollectionWith(session, [mainTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dtsMap deleted", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dtsMap deleted", session); }); it(`with depedency .d.ts file, when file is not present`, () => { @@ -1035,7 +1037,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dts not present", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dts not present", session); }); it(`with depedency .d.ts file, when file is created after actions on projects`, () => { let fileContents: string; @@ -1054,7 +1056,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ false ); verifyScriptInfoCollectionWith(session, [mainTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dts created", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dts created", session); }); it(`with depedency .d.ts file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -1070,7 +1072,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dts deleted", session); + baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dts deleted", session); }); }); }); @@ -1102,7 +1104,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ false ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/rename locations", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/rename locations", session); }); // Edit @@ -1124,7 +1126,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/usage file changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/usage file changes with timeout before request", session); }); it(`when usage file changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1142,7 +1144,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/usage file changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/usage file changes", session); }); // Edit dts to add new fn @@ -1164,7 +1166,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dts changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dts changes with timeout before request", session); }); it(`when dependency .d.ts changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1182,7 +1184,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dts changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dts changes", session); }); // Edit map file to represent added new line @@ -1204,7 +1206,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ false ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dtsMap changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dtsMap changes with timeout before request", session); }); it(`when dependency file's map changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1222,7 +1224,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ false ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dtsMap changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dtsMap changes", session); }); it(`with depedency files map file, when file is not present`, () => { @@ -1237,7 +1239,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dtsMap not present", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dtsMap not present", session); }); it(`with depedency files map file, when file is created after actions on projects`, () => { let fileContents: string; @@ -1256,7 +1258,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ false ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dtsMap created", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dtsMap created", session); }); it(`with depedency files map file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -1272,7 +1274,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ false ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dtsMap deleted", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dtsMap deleted", session); }); it(`with depedency .d.ts file, when file is not present`, () => { @@ -1287,7 +1289,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dts not present", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dts not present", session); }); it(`with depedency .d.ts file, when file is created after actions on projects`, () => { let fileContents: string; @@ -1306,7 +1308,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ false ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dts created", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dts created", session); }); it(`with depedency .d.ts file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -1322,7 +1324,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dts deleted", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dts deleted", session); }); }); describe("when main tsconfig has project reference", () => { @@ -1345,7 +1347,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ false ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/rename locations", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/rename locations", session); }); // Edit @@ -1367,7 +1369,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/usage file changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/usage file changes with timeout before request", session); }); it(`when usage file changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1385,7 +1387,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/usage file changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/usage file changes", session); }); // Edit dts to add new fn @@ -1407,7 +1409,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dts changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dts changes with timeout before request", session); }); it(`when dependency .d.ts changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1425,7 +1427,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dts changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dts changes", session); }); // Edit map file to represent added new line @@ -1447,7 +1449,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ false ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dtsMap changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dtsMap changes with timeout before request", session); }); it(`when dependency file's map changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1465,7 +1467,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ false ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dtsMap changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dtsMap changes", session); }); it(`with depedency files map file, when file is not present`, () => { @@ -1480,7 +1482,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dtsMap not present", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dtsMap not present", session); }); it(`with depedency files map file, when file is created after actions on projects`, () => { let fileContents: string; @@ -1499,7 +1501,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ false ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dtsMap created", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dtsMap created", session); }); it(`with depedency files map file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -1515,7 +1517,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ false ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dtsMap deleted", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dtsMap deleted", session); }); it(`with depedency .d.ts file, when file is not present`, () => { @@ -1530,7 +1532,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dts not present", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dts not present", session); }); it(`with depedency .d.ts file, when file is created after actions on projects`, () => { let fileContents: string; @@ -1549,7 +1551,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ false ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dts created", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dts created", session); }); it(`with depedency .d.ts file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -1565,7 +1567,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dts deleted", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dts deleted", session); }); it(`when defining project source changes, when timeout occurs before request`, () => { // Create DocumentPositionMapper @@ -1573,8 +1575,8 @@ ${dependencyTs.content}`); // change // Make change, without rebuild of solution - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: dependencyTs.path, line: 1, offset: 1, endLine: 1, endOffset: 1, insertString: `function fooBar() { } `} @@ -1591,7 +1593,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ false, /*existingDocumentPositionMapperEqual*/ false ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency source changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency source changes with timeout before request", session); }); it(`when defining project source changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1599,8 +1601,8 @@ ${dependencyTs.content}`); // change // Make change, without rebuild of solution - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: dependencyTs.path, line: 1, offset: 1, endLine: 1, endOffset: 1, insertString: `function fooBar() { } `} @@ -1615,13 +1617,13 @@ ${dependencyTs.content}`); /*existingMapEqual*/ false, /*existingDocumentPositionMapperEqual*/ false ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency source changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency source changes", session); }); it("when projects are not built", () => { - const host = ts.projectSystem.createServerHost(files); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([dependencyTs, randomFile], session); + const host = createServerHost(files); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([dependencyTs, randomFile], session); verifyAllFnAction( session, renameFromDependencyTs, @@ -1631,7 +1633,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/when projects are not built", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/when projects are not built", session); }); }); describe("when main tsconfig has disableSourceOfProjectReferenceRedirect along with project reference", () => { @@ -1654,7 +1656,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ false ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/rename locations", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/rename locations", session); }); // Edit @@ -1676,7 +1678,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/usage file changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/usage file changes with timeout before request", session); }); it(`when usage file changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1694,7 +1696,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/usage file changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/usage file changes", session); }); // Edit dts to add new fn @@ -1716,7 +1718,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dts changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dts changes with timeout before request", session); }); it(`when dependency .d.ts changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1734,7 +1736,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dts changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dts changes", session); }); // Edit map file to represent added new line @@ -1756,7 +1758,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ false ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dtsMap changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dtsMap changes with timeout before request", session); }); it(`when dependency file's map changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1774,7 +1776,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ false ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dtsMap changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dtsMap changes", session); }); it(`with depedency files map file, when file is not present`, () => { @@ -1789,7 +1791,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dtsMap not present", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dtsMap not present", session); }); it(`with depedency files map file, when file is created after actions on projects`, () => { let fileContents: string; @@ -1808,7 +1810,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ false ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dtsMap created", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dtsMap created", session); }); it(`with depedency files map file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -1824,7 +1826,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ false ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dtsMap deleted", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dtsMap deleted", session); }); it(`with depedency .d.ts file, when file is not present`, () => { @@ -1839,7 +1841,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dts not present", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dts not present", session); }); it(`with depedency .d.ts file, when file is created after actions on projects`, () => { let fileContents: string; @@ -1858,7 +1860,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ false ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dts created", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dts created", session); }); it(`with depedency .d.ts file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -1874,7 +1876,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dts deleted", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dts deleted", session); }); }); }); @@ -1916,7 +1918,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/goToDef and rename locations", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/goToDef and rename locations", session); }); // Edit @@ -1947,7 +1949,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/usage file changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/usage file changes with timeout before request", session); }); it(`when usage file changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1974,7 +1976,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/usage file changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/usage file changes", session); }); // Edit dts to add new fn @@ -2004,7 +2006,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dts changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dts changes with timeout before request", session); }); it(`when dependency .d.ts changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -2030,7 +2032,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dts changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dts changes", session); }); // Edit map file to represent added new line @@ -2061,7 +2063,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dtsMap changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dtsMap changes with timeout before request", session); }); it(`when dependency file's map changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -2088,7 +2090,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dtsMap changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dtsMap changes", session); }); it(`with depedency files map file, when file is not present`, () => { @@ -2111,7 +2113,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dtsMap not present", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dtsMap not present", session); }); it(`with depedency files map file, when file is created after actions on projects`, () => { let fileContents: string; @@ -2139,7 +2141,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dtsMap created", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dtsMap created", session); }); it(`with depedency files map file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -2164,7 +2166,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dtsMap deleted", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dtsMap deleted", session); }); it(`with depedency .d.ts file, when file is not present`, () => { @@ -2186,7 +2188,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dts not present", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dts not present", session); }); it(`with depedency .d.ts file, when file is created after actions on projects`, () => { let fileContents: string; @@ -2214,7 +2216,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dts created", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dts created", session); }); it(`with depedency .d.ts file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -2238,7 +2240,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dts deleted", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dts deleted", session); }); }); describe("when main tsconfig has project reference", () => { @@ -2269,7 +2271,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ false ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/gotoDef and rename locations", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/gotoDef and rename locations", session); }); // Edit @@ -2300,7 +2302,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/usage file changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/usage file changes with timeout before request", session); }); it(`when usage file changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -2327,7 +2329,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/usage file changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/usage file changes", session); }); // Edit dts to add new fn @@ -2357,7 +2359,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dts changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dts changes with timeout before request", session); }); it(`when dependency .d.ts changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -2383,7 +2385,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dts changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dts changes", session); }); // Edit map file to represent added new line @@ -2413,7 +2415,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ false ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dtsMap changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dtsMap changes with timeout before request", session); }); it(`when dependency file's map changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -2439,7 +2441,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ false ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dtsMap changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dtsMap changes", session); }); it(`with depedency files map file, when file is not present`, () => { @@ -2462,7 +2464,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dtsMap not present", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dtsMap not present", session); }); it(`with depedency files map file, when file is created after actions on projects`, () => { let fileContents: string; @@ -2490,7 +2492,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ false ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dtsMap created", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dtsMap created", session); }); it(`with depedency files map file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -2515,7 +2517,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ false ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dtsMap deleted", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dtsMap deleted", session); }); it(`with depedency .d.ts file, when file is not present`, () => { @@ -2538,7 +2540,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dts not present", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dts not present", session); }); it(`with depedency .d.ts file, when file is created after actions on projects`, () => { let fileContents: string; @@ -2565,7 +2567,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ false ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dts created", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dts created", session); }); it(`with depedency .d.ts file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -2589,7 +2591,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dts deleted", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dts deleted", session); }); it(`when defining project source changes, when timeout occurs before request`, () => { // Create DocumentPositionMapper @@ -2597,8 +2599,8 @@ ${dependencyTs.content}`); // change // Make change, without rebuild of solution - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: dependencyTs.path, line: 1, offset: 1, endLine: 1, endOffset: 1, insertString: `function fooBar() { } `} @@ -2623,7 +2625,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency source changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency source changes with timeout before request", session); }); it(`when defining project source changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -2631,8 +2633,8 @@ ${dependencyTs.content}`); // change // Make change, without rebuild of solution - session.executeCommandSeq({ - command: ts.projectSystem.protocol.CommandTypes.Change, + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Change, arguments: { file: dependencyTs.path, line: 1, offset: 1, endLine: 1, endOffset: 1, insertString: `function fooBar() { } `} @@ -2655,13 +2657,13 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency source changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency source changes", session); }); it("when projects are not built", () => { - const host = ts.projectSystem.createServerHost(files); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([mainTs, dependencyTs, randomFile], session); + const host = createServerHost(files); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([mainTs, dependencyTs, randomFile], session); verifyAllFnAction( session, goToDefFromMainTs, @@ -2679,7 +2681,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/when projects are not built", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/when projects are not built", session); }); }); describe("when main tsconfig has disableSourceOfProjectReferenceRedirect along with project reference", () => { @@ -2711,7 +2713,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/gotoDef and rename locations", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/gotoDef and rename locations", session); }); // Edit @@ -2742,7 +2744,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/usage file changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/usage file changes with timeout before request", session); }); it(`when usage file changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -2769,7 +2771,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/usage file changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/usage file changes", session); }); // Edit dts to add new fn @@ -2799,7 +2801,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dts changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dts changes with timeout before request", session); }); it(`when dependency .d.ts changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -2825,7 +2827,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dts changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dts changes", session); }); // Edit map file to represent added new line @@ -2856,7 +2858,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dtsMap changes with timeout before request", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dtsMap changes with timeout before request", session); }); it(`when dependency file's map changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -2883,7 +2885,7 @@ ${dependencyTs.content}`); /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true ); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dtsMap changes", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dtsMap changes", session); }); it(`with depedency files map file, when file is not present`, () => { @@ -2906,7 +2908,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dtsMap not present", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dtsMap not present", session); }); it(`with depedency files map file, when file is created after actions on projects`, () => { let fileContents: string; @@ -2934,7 +2936,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dtsMap created", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dtsMap created", session); }); it(`with depedency files map file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -2959,7 +2961,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dtsMap deleted", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dtsMap deleted", session); }); it(`with depedency .d.ts file, when file is not present`, () => { @@ -2982,7 +2984,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dts not present", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dts not present", session); }); it(`with depedency .d.ts file, when file is created after actions on projects`, () => { let fileContents: string; @@ -3010,7 +3012,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dts created", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dts created", session); }); it(`with depedency .d.ts file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -3034,7 +3036,7 @@ ${dependencyTs.content}`); /*existingDocumentPositionMapperEqual*/ true ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - ts.projectSystem.baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dts deleted", session); + baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dts deleted", session); }); }); }); diff --git a/src/testRunner/unittests/tsserver/projects.ts b/src/testRunner/unittests/tsserver/projects.ts index a683a561738..35984a67078 100644 --- a/src/testRunner/unittests/tsserver/projects.ts +++ b/src/testRunner/unittests/tsserver/projects.ts @@ -1,17 +1,20 @@ import * as ts from "../../_namespaces/ts"; +import { createServerHost, File, libFile } from "../virtualFileSystemWithWatch"; +import { commonFile1, commonFile2 } from "../tscWatch/helpers"; +import { createSession, createLoggerWithInMemoryLogs, openFilesForSession, makeSessionRequest, baselineTsserverLogs, createProjectService, configuredProjectAt, checkProjectRootFiles, checkNumberOfConfiguredProjects, checkNumberOfInferredProjects, toExternalFiles, checkNumberOfProjects, checkProjectActualFiles, customTypesMap, toExternalFile, closeFilesForSession, verifyGetErrRequest, protocolFileLocationFromSubstring } from "./helpers"; describe("unittests:: tsserver:: Projects", () => { it("handles the missing files - that were added to program because they were added with /// { - const file1: ts.projectSystem.File = { + const file1: File = { path: "/a/b/commonFile1.ts", content: `/// let x = y` }; - const host = ts.projectSystem.createServerHost([file1, ts.projectSystem.libFile]); - const session = ts.projectSystem.createSession(host, { logger: ts.projectSystem.createLoggerWithInMemoryLogs(host) }); - ts.projectSystem.openFilesForSession([file1], session); + const host = createServerHost([file1, libFile]); + const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); + openFilesForSession([file1], session); - const getErrRequest = ts.projectSystem.makeSessionRequest( + const getErrRequest = makeSessionRequest( ts.server.CommandNames.SemanticDiagnosticsSync, { file: file1.path } ); @@ -19,41 +22,41 @@ describe("unittests:: tsserver:: Projects", () => { // Two errors: CommonFile2 not found and cannot find name y session.executeCommand(getErrRequest); - host.writeFile(ts.projectSystem.commonFile2.path, ts.projectSystem.commonFile2.content); + host.writeFile(commonFile2.path, commonFile2.content); host.runQueuedTimeoutCallbacks(); session.executeCommand(getErrRequest); - ts.projectSystem.baselineTsserverLogs("projects", "handles the missing files added with tripleslash ref", session); + baselineTsserverLogs("projects", "handles the missing files added with tripleslash ref", session); }); it("should create new inferred projects for files excluded from a configured project", () => { - const configFile: ts.projectSystem.File = { + const configFile: File = { path: "/a/b/tsconfig.json", content: `{ "compilerOptions": {}, - "files": ["${ts.projectSystem.commonFile1.path}", "${ts.projectSystem.commonFile2.path}"] + "files": ["${commonFile1.path}", "${commonFile2.path}"] }` }; - const files = [ts.projectSystem.commonFile1, ts.projectSystem.commonFile2, configFile]; - const host = ts.projectSystem.createServerHost(files); - const projectService = ts.projectSystem.createProjectService(host); - projectService.openClientFile(ts.projectSystem.commonFile1.path); + const files = [commonFile1, commonFile2, configFile]; + const host = createServerHost(files); + const projectService = createProjectService(host); + projectService.openClientFile(commonFile1.path); - const project = ts.projectSystem.configuredProjectAt(projectService, 0); - ts.projectSystem.checkProjectRootFiles(project, [ts.projectSystem.commonFile1.path, ts.projectSystem.commonFile2.path]); + const project = configuredProjectAt(projectService, 0); + checkProjectRootFiles(project, [commonFile1.path, commonFile2.path]); configFile.content = `{ "compilerOptions": {}, - "files": ["${ts.projectSystem.commonFile1.path}"] + "files": ["${commonFile1.path}"] }`; host.writeFile(configFile.path, configFile.content); - ts.projectSystem.checkNumberOfConfiguredProjects(projectService, 1); - ts.projectSystem.checkProjectRootFiles(project, [ts.projectSystem.commonFile1.path, ts.projectSystem.commonFile2.path]); + checkNumberOfConfiguredProjects(projectService, 1); + checkProjectRootFiles(project, [commonFile1.path, commonFile2.path]); host.checkTimeoutQueueLengthAndRun(2); // Update the configured project + refresh inferred projects - ts.projectSystem.checkNumberOfConfiguredProjects(projectService, 1); - ts.projectSystem.checkProjectRootFiles(project, [ts.projectSystem.commonFile1.path]); + checkNumberOfConfiguredProjects(projectService, 1); + checkProjectRootFiles(project, [commonFile1.path]); - projectService.openClientFile(ts.projectSystem.commonFile2.path); - ts.projectSystem.checkNumberOfInferredProjects(projectService, 1); + projectService.openClientFile(commonFile2.path); + checkNumberOfInferredProjects(projectService, 1); }); it("should disable features when the files are too large", () => { @@ -75,18 +78,18 @@ describe("unittests:: tsserver:: Projects", () => { const proj1name = "proj1", proj2name = "proj2", proj3name = "proj3"; - 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({ rootFiles: ts.projectSystem.toExternalFiles([file1.path]), options: {}, projectFileName: proj1name }); + projectService.openExternalProject({ rootFiles: toExternalFiles([file1.path]), options: {}, projectFileName: proj1name }); const proj1 = projectService.findProject(proj1name)!; assert.isTrue(proj1.languageServiceEnabled); - projectService.openExternalProject({ rootFiles: ts.projectSystem.toExternalFiles([file2.path]), options: {}, projectFileName: proj2name }); + projectService.openExternalProject({ rootFiles: toExternalFiles([file2.path]), options: {}, projectFileName: proj2name }); const proj2 = projectService.findProject(proj2name)!; assert.isTrue(proj2.languageServiceEnabled); - projectService.openExternalProject({ rootFiles: ts.projectSystem.toExternalFiles([file3.path]), options: {}, projectFileName: proj3name }); + projectService.openExternalProject({ rootFiles: toExternalFiles([file3.path]), options: {}, projectFileName: proj3name }); const proj3 = projectService.findProject(proj3name)!; assert.isFalse(proj3.languageServiceEnabled); }); @@ -105,10 +108,10 @@ describe("unittests:: tsserver:: Projects", () => { const projName = "proj1"; - const host = ts.projectSystem.createServerHost([file1, file2]); - const projectService = ts.projectSystem.createProjectService(host, { useSingleInferredProject: true, eventHandler: ts.noop }); + const host = createServerHost([file1, file2]); + const projectService = createProjectService(host, { useSingleInferredProject: true, eventHandler: ts.noop }); - projectService.openExternalProject({ rootFiles: ts.projectSystem.toExternalFiles([file1.path, file2.path]), options: {}, projectFileName: projName }); + projectService.openExternalProject({ rootFiles: toExternalFiles([file1.path, file2.path]), options: {}, projectFileName: projName }); const proj1 = projectService.findProject(projName)!; assert.isFalse(proj1.languageServiceEnabled); @@ -132,15 +135,15 @@ describe("unittests:: tsserver:: Projects", () => { }; const externalProjectName = "externalproject"; - const host = ts.projectSystem.createServerHost([file1, config1]); - const projectService = ts.projectSystem.createProjectService(host, { useSingleInferredProject: true, syntaxOnly: true }); + const host = createServerHost([file1, config1]); + const projectService = createProjectService(host, { useSingleInferredProject: true, syntaxOnly: true }); projectService.openExternalProject({ - rootFiles: ts.projectSystem.toExternalFiles([file1.path, config1.path]), + rootFiles: toExternalFiles([file1.path, config1.path]), options: {}, projectFileName: externalProjectName }); - ts.projectSystem.checkNumberOfProjects(projectService, { externalProjects: 1 }); + checkNumberOfProjects(projectService, { externalProjects: 1 }); const proj = projectService.externalProjects[0]; assert.isDefined(proj); @@ -162,11 +165,11 @@ describe("unittests:: tsserver:: Projects", () => { ) }; - const host = ts.projectSystem.createServerHost([file1, config1]); - const projectService = ts.projectSystem.createProjectService(host, { useSingleInferredProject: true, syntaxOnly: true }); + const host = createServerHost([file1, config1]); + const projectService = createProjectService(host, { useSingleInferredProject: true, syntaxOnly: true }); projectService.openClientFile(file1.path, file1.content); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 1 }); + checkNumberOfProjects(projectService, { inferredProjects: 1 }); const proj = projectService.inferredProjects[0]; assert.isDefined(proj); @@ -188,11 +191,11 @@ describe("unittests:: tsserver:: Projects", () => { ) }; - const host = ts.projectSystem.createServerHost([file1, config1]); - const projectService = ts.projectSystem.createProjectService(host, { useSingleInferredProject: true, syntaxOnly: true }); + const host = createServerHost([file1, config1]); + const projectService = createProjectService(host, { useSingleInferredProject: true, syntaxOnly: true }); projectService.applyChangesInOpenFiles(ts.singleIterator({ fileName: file1.path, content: file1.content })); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 1 }); + checkNumberOfProjects(projectService, { inferredProjects: 1 }); const proj = projectService.inferredProjects[0]; assert.isDefined(proj); @@ -210,15 +213,15 @@ describe("unittests:: tsserver:: Projects", () => { content: "let x: number;" }; - const host = ts.projectSystem.createServerHost([f1, f2, ts.projectSystem.libFile]); - const service = ts.projectSystem.createProjectService(host); - service.openExternalProject({ projectFileName: "/a/b/project", rootFiles: ts.projectSystem.toExternalFiles([f1.path, f2.path]), options: {} }); + const host = createServerHost([f1, f2, libFile]); + const service = createProjectService(host); + service.openExternalProject({ projectFileName: "/a/b/project", rootFiles: toExternalFiles([f1.path, f2.path]), options: {} }); service.openClientFile(f1.path); service.openClientFile(f2.path, "let x: string"); service.checkNumberOfProjects({ externalProjects: 1 }); - ts.projectSystem.checkProjectActualFiles(service.externalProjects[0], [f1.path, f2.path, ts.projectSystem.libFile.path]); + checkProjectActualFiles(service.externalProjects[0], [f1.path, f2.path, libFile.path]); const completions1 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 2, ts.emptyOptions)!; // should contain completions for string @@ -242,15 +245,15 @@ describe("unittests:: tsserver:: Projects", () => { content: "" }; - const host = ts.projectSystem.createServerHost([f1, f2, ts.projectSystem.libFile]); - const service = ts.projectSystem.createProjectService(host); + const host = createServerHost([f1, f2, libFile]); + const service = createProjectService(host); service.openExternalProject({ projectFileName: "/a/b/project", rootFiles: [{ fileName: f1.path }, { fileName: f2.path, hasMixedContent: true }], options: {} }); service.openClientFile(f1.path); service.openClientFile(f2.path, "let somelongname: string"); service.checkNumberOfProjects({ externalProjects: 1 }); - ts.projectSystem.checkProjectActualFiles(service.externalProjects[0], [f1.path, f2.path, ts.projectSystem.libFile.path]); + checkProjectActualFiles(service.externalProjects[0], [f1.path, f2.path, libFile.path]); const completions1 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 0, ts.emptyOptions)!; assert.isTrue(completions1.entries.some(e => e.name === "somelongname"), "should contain 'somelongname'"); @@ -275,26 +278,26 @@ describe("unittests:: tsserver:: Projects", () => { path: "/a/c/f3.ts", 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.openClientFile(file1.path); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 1 }); + checkNumberOfProjects(projectService, { inferredProjects: 1 }); const inferredProject0 = projectService.inferredProjects[0]; - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[0], [file1.path, file2.path]); + checkProjectActualFiles(projectService.inferredProjects[0], [file1.path, file2.path]); projectService.openClientFile(file3.path); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 2 }); + checkNumberOfProjects(projectService, { inferredProjects: 2 }); assert.strictEqual(projectService.inferredProjects[0], inferredProject0); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[0], [file1.path, file2.path]); + checkProjectActualFiles(projectService.inferredProjects[0], [file1.path, file2.path]); const inferredProject1 = projectService.inferredProjects[1]; - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[1], [file3.path]); + checkProjectActualFiles(projectService.inferredProjects[1], [file3.path]); host.writeFile(file2.path, `export * from "../c/f3"`); // now inferred project should inclule file3 host.checkTimeoutQueueLengthAndRun(2); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 2 }); + checkNumberOfProjects(projectService, { inferredProjects: 2 }); assert.strictEqual(projectService.inferredProjects[0], inferredProject0); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[0], [file1.path, file2.path, file3.path]); + checkProjectActualFiles(projectService.inferredProjects[0], [file1.path, file2.path, file3.path]); assert.strictEqual(projectService.inferredProjects[1], inferredProject1); assert.isTrue(inferredProject1.isOrphan()); }); @@ -312,25 +315,25 @@ describe("unittests:: tsserver:: Projects", () => { path: "/a/c/f3.ts", 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.openClientFile(file1.path); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 1 }); + checkNumberOfProjects(projectService, { inferredProjects: 1 }); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[0], [file1.path, file2.path, file3.path]); + checkProjectActualFiles(projectService.inferredProjects[0], [file1.path, file2.path, file3.path]); projectService.openClientFile(file3.path); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 1 }); + checkNumberOfProjects(projectService, { inferredProjects: 1 }); host.deleteFile(file2.path); host.checkTimeoutQueueLengthAndRun(2); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 2 }); + checkNumberOfProjects(projectService, { inferredProjects: 2 }); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[0], [file1.path]); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[1], [file3.path]); + checkProjectActualFiles(projectService.inferredProjects[0], [file1.path]); + checkProjectActualFiles(projectService.inferredProjects[1], [file3.path]); }); it("ignores files excluded by a custom safe type list", () => { @@ -342,10 +345,10 @@ describe("unittests:: tsserver:: Projects", () => { path: "/lib/duckquack-3.min.js", content: "whoa do @@ not parse me ok thanks!!!" }; - const host = ts.projectSystem.createServerHost([file1, office, ts.projectSystem.customTypesMap]); - const projectService = ts.projectSystem.createProjectService(host); + const host = createServerHost([file1, office, customTypesMap]); + const projectService = createProjectService(host); try { - projectService.openExternalProject({ projectFileName: "project", options: {}, rootFiles: ts.projectSystem.toExternalFiles([file1.path, office.path]) }); + projectService.openExternalProject({ projectFileName: "project", options: {}, rootFiles: toExternalFiles([file1.path, office.path]) }); const proj = projectService.externalProjects[0]; assert.deepEqual(proj.getFileNames(/*excludeFilesFromExternalLibraries*/ true), [file1.path]); assert.deepEqual(proj.getTypeAcquisition().include, ["duck-types"]); @@ -368,7 +371,7 @@ describe("unittests:: tsserver:: Projects", () => { path: "/a/b/bliss.js", content: "export function is() { return true; }" }; - const host = ts.projectSystem.createServerHost([file1, ts.projectSystem.libFile, constructorFile, bliss, ts.projectSystem.customTypesMap]); + const host = createServerHost([file1, libFile, constructorFile, bliss, customTypesMap]); let request: string | undefined; const cachePath = "/a/data"; const typingsInstaller: ts.server.ITypingsInstaller = { @@ -384,11 +387,11 @@ describe("unittests:: tsserver:: Projects", () => { }; const projectName = "project"; - const projectService = ts.projectSystem.createProjectService(host, { typingsInstaller }); - projectService.openExternalProject({ projectFileName: projectName, options: {}, rootFiles: ts.projectSystem.toExternalFiles([file1.path, constructorFile.path, bliss.path]) }); + const projectService = createProjectService(host, { typingsInstaller }); + projectService.openExternalProject({ projectFileName: projectName, options: {}, rootFiles: toExternalFiles([file1.path, constructorFile.path, bliss.path]) }); assert.equal(request, JSON.stringify({ projectName, - fileNames: [ts.projectSystem.libFile.path, file1.path, constructorFile.path, bliss.path], + fileNames: [libFile.path, file1.path, constructorFile.path, bliss.path], compilerOptions: { allowNonTsExtensions: true, noEmitForJsFiles: true }, typeAcquisition: { include: ["blissfuljs"], exclude: [], enable: true }, unresolvedImports: ["s"], @@ -441,10 +444,10 @@ describe("unittests:: tsserver:: Projects", () => { content: "unspecified" }; const files = [file1, minFile, kendoFile1, kendoFile2, kendoFile3, officeFile1, officeFile2]; - const host = ts.projectSystem.createServerHost(files); - const projectService = ts.projectSystem.createProjectService(host); + const host = createServerHost(files); + const projectService = createProjectService(host); try { - projectService.openExternalProject({ projectFileName: "project", options: {}, rootFiles: ts.projectSystem.toExternalFiles(files.map(f => f.path)) }); + projectService.openExternalProject({ projectFileName: "project", options: {}, rootFiles: toExternalFiles(files.map(f => f.path)) }); const proj = projectService.externalProjects[0]; assert.deepEqual(proj.getFileNames(/*excludeFilesFromExternalLibraries*/ true), [file1.path]); assert.deepEqual(proj.getTypeAcquisition().include, ["kendo-ui", "office"]); @@ -483,10 +486,10 @@ describe("unittests:: tsserver:: Projects", () => { path: "/a/b/Bacon.js", content: "let y = 5" }; - const host = ts.projectSystem.createServerHost([file1, file2, file3, ts.projectSystem.customTypesMap]); - const projectService = ts.projectSystem.createProjectService(host); + const host = createServerHost([file1, file2, file3, customTypesMap]); + const projectService = createProjectService(host); try { - projectService.openExternalProject({ projectFileName: "project", options: {}, rootFiles: ts.projectSystem.toExternalFiles([file1.path, file2.path]), typeAcquisition: { enable: true } }); + projectService.openExternalProject({ projectFileName: "project", options: {}, rootFiles: toExternalFiles([file1.path, file2.path]), typeAcquisition: { enable: true } }); const proj = projectService.externalProjects[0]; assert.deepEqual(proj.getFileNames(), [file2.path]); } @@ -510,52 +513,52 @@ describe("unittests:: tsserver:: Projects", () => { path: "/a/d/f3.ts", 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.openClientFile(file2.path); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 1 }); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[0], [file2.path]); + checkNumberOfProjects(projectService, { inferredProjects: 1 }); + checkProjectActualFiles(projectService.inferredProjects[0], [file2.path]); let inferredProjects = projectService.inferredProjects.slice(); projectService.openClientFile(file3.path); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 2 }); + checkNumberOfProjects(projectService, { inferredProjects: 2 }); assert.strictEqual(projectService.inferredProjects[0], inferredProjects[0]); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[0], [file2.path]); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[1], [file3.path]); + checkProjectActualFiles(projectService.inferredProjects[0], [file2.path]); + checkProjectActualFiles(projectService.inferredProjects[1], [file3.path]); inferredProjects = projectService.inferredProjects.slice(); projectService.openClientFile(file1.path); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 1 }); + checkNumberOfProjects(projectService, { inferredProjects: 1 }); assert.notStrictEqual(projectService.inferredProjects[0], inferredProjects[0]); assert.notStrictEqual(projectService.inferredProjects[0], inferredProjects[1]); - ts.projectSystem.checkProjectRootFiles(projectService.inferredProjects[0], [file1.path]); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[0], [file1.path, file2.path, file3.path]); + checkProjectRootFiles(projectService.inferredProjects[0], [file1.path]); + checkProjectActualFiles(projectService.inferredProjects[0], [file1.path, file2.path, file3.path]); inferredProjects = projectService.inferredProjects.slice(); projectService.closeClientFile(file1.path); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 3 }); + checkNumberOfProjects(projectService, { inferredProjects: 3 }); assert.strictEqual(projectService.inferredProjects[0], inferredProjects[0]); assert.isTrue(projectService.inferredProjects[0].isOrphan()); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[1], [file2.path]); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[2], [file3.path]); + checkProjectActualFiles(projectService.inferredProjects[1], [file2.path]); + checkProjectActualFiles(projectService.inferredProjects[2], [file3.path]); inferredProjects = projectService.inferredProjects.slice(); projectService.closeClientFile(file3.path); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 3 }); + checkNumberOfProjects(projectService, { inferredProjects: 3 }); assert.strictEqual(projectService.inferredProjects[0], inferredProjects[0]); assert.strictEqual(projectService.inferredProjects[1], inferredProjects[1]); assert.strictEqual(projectService.inferredProjects[2], inferredProjects[2]); assert.isTrue(projectService.inferredProjects[0].isOrphan()); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[1], [file2.path]); + checkProjectActualFiles(projectService.inferredProjects[1], [file2.path]); assert.isTrue(projectService.inferredProjects[2].isOrphan()); projectService.openClientFile(file3.path); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 2 }); + checkNumberOfProjects(projectService, { inferredProjects: 2 }); assert.strictEqual(projectService.inferredProjects[0], inferredProjects[2]); assert.strictEqual(projectService.inferredProjects[1], inferredProjects[1]); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[0], [file3.path]); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[1], [file2.path]); + checkProjectActualFiles(projectService.inferredProjects[0], [file3.path]); + checkProjectActualFiles(projectService.inferredProjects[1], [file2.path]); }); it("regression test for crash in acquireOrUpdateDocument", () => { @@ -571,8 +574,8 @@ describe("unittests:: tsserver:: Projects", () => { scriptKind: "JS" as const }; - const host = ts.projectSystem.createServerHost([]); - const projectService = ts.projectSystem.createProjectService(host); + const host = createServerHost([]); + const projectService = createProjectService(host); projectService.applyChangesInOpenFiles(ts.singleIterator(tsFile)); const projs = projectService.synchronizeProjectList([]); projectService.findProject(projs[0].info!.projectName)!.getLanguageService().getNavigationBarItems(tsFile.fileName); @@ -593,22 +596,22 @@ describe("unittests:: tsserver:: Projects", () => { path: "/a/b/tsconfig.json", content: JSON.stringify({ compilerOptions: {} }) }; - const host = ts.projectSystem.createServerHost([file1, file2, config]); - const projectService = ts.projectSystem.createProjectService(host); + const host = createServerHost([file1, file2, config]); + const projectService = createProjectService(host); projectService.openClientFile(file1.path); - ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 }); - ts.projectSystem.checkProjectActualFiles(ts.projectSystem.configuredProjectAt(projectService, 0), [file1.path, file2.path, config.path]); + checkNumberOfProjects(projectService, { configuredProjects: 1 }); + checkProjectActualFiles(configuredProjectAt(projectService, 0), [file1.path, file2.path, config.path]); projectService.openClientFile(file2.path); - ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 }); - ts.projectSystem.checkProjectActualFiles(ts.projectSystem.configuredProjectAt(projectService, 0), [file1.path, file2.path, config.path]); + checkNumberOfProjects(projectService, { configuredProjects: 1 }); + checkProjectActualFiles(configuredProjectAt(projectService, 0), [file1.path, file2.path, config.path]); host.deleteFile(config.path); host.checkTimeoutQueueLengthAndRun(1); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 2 }); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[0], [file1.path]); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[1], [file2.path]); + checkNumberOfProjects(projectService, { inferredProjects: 2 }); + checkProjectActualFiles(projectService.inferredProjects[0], [file1.path]); + checkProjectActualFiles(projectService.inferredProjects[1], [file2.path]); }); it("loading files with correct priority", () => { @@ -630,8 +633,8 @@ describe("unittests:: tsserver:: Projects", () => { compilerOptions: { allowJs: true } }) }; - const host = ts.projectSystem.createServerHost([f1, f2, f3, config]); - const projectService = ts.projectSystem.createProjectService(host); + const host = createServerHost([f1, f2, f3, config]); + const projectService = createProjectService(host); projectService.setHostConfiguration({ extraFileExtensions: [ { extension: ".js", isMixedContent: false }, @@ -640,21 +643,21 @@ describe("unittests:: tsserver:: Projects", () => { }); projectService.openClientFile(f1.path); projectService.checkNumberOfProjects({ configuredProjects: 1 }); - ts.projectSystem.checkProjectActualFiles(ts.projectSystem.configuredProjectAt(projectService, 0), [f1.path, config.path]); + checkProjectActualFiles(configuredProjectAt(projectService, 0), [f1.path, config.path]); // Since f2 refers to config file as the default project, it needs to be kept alive projectService.closeClientFile(f1.path); projectService.openClientFile(f2.path); projectService.checkNumberOfProjects({ inferredProjects: 1, configuredProjects: 1 }); assert.isDefined(projectService.configuredProjects.get(config.path)); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[0], [f2.path]); + checkProjectActualFiles(projectService.inferredProjects[0], [f2.path]); // Should close configured project with next file open projectService.closeClientFile(f2.path); projectService.openClientFile(f3.path); projectService.checkNumberOfProjects({ inferredProjects: 1 }); assert.isUndefined(projectService.configuredProjects.get(config.path)); - ts.projectSystem.checkProjectActualFiles(projectService.inferredProjects[0], [f3.path]); + checkProjectActualFiles(projectService.inferredProjects[0], [f3.path]); }); it("tsconfig script block support", () => { @@ -670,25 +673,25 @@ describe("unittests:: tsserver:: Projects", () => { path: "/a/b/tsconfig.json", content: JSON.stringify({ compilerOptions: { allowJs: true } }) }; - const host = ts.projectSystem.createServerHost([file1, file2, config]); - const session = ts.projectSystem.createSession(host); - ts.projectSystem.openFilesForSession([file1], session); + const host = createServerHost([file1, file2, config]); + const session = createSession(host); + openFilesForSession([file1], session); const projectService = session.getProjectService(); // HTML file will not be included in any projects yet - ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 }); - const configuredProj = ts.projectSystem.configuredProjectAt(projectService, 0); - ts.projectSystem.checkProjectActualFiles(configuredProj, [file1.path, config.path]); + checkNumberOfProjects(projectService, { configuredProjects: 1 }); + const configuredProj = configuredProjectAt(projectService, 0); + checkProjectActualFiles(configuredProj, [file1.path, config.path]); // Specify .html extension as mixed content const extraFileExtensions = [{ extension: ".html", scriptKind: ts.ScriptKind.JS, isMixedContent: true }]; - const configureHostRequest = ts.projectSystem.makeSessionRequest(ts.projectSystem.CommandNames.Configure, { extraFileExtensions }); + const configureHostRequest = makeSessionRequest(ts.server.CommandNames.Configure, { extraFileExtensions }); session.executeCommand(configureHostRequest); // The configured project should now be updated to include html file - ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 }); - assert.strictEqual(ts.projectSystem.configuredProjectAt(projectService, 0), configuredProj, "Same configured project should be updated"); - ts.projectSystem.checkProjectActualFiles(ts.projectSystem.configuredProjectAt(projectService, 0), [file1.path, file2.path, config.path]); + checkNumberOfProjects(projectService, { configuredProjects: 1 }); + assert.strictEqual(configuredProjectAt(projectService, 0), configuredProj, "Same configured project should be updated"); + checkProjectActualFiles(configuredProjectAt(projectService, 0), [file1.path, file2.path, config.path]); // Open HTML file projectService.applyChangesInOpenFiles(ts.singleIterator({ @@ -698,11 +701,11 @@ describe("unittests:: tsserver:: Projects", () => { content: `var hello = "hello";` })); // Now HTML file is included in the project - ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 }); - ts.projectSystem.checkProjectActualFiles(ts.projectSystem.configuredProjectAt(projectService, 0), [file1.path, file2.path, config.path]); + checkNumberOfProjects(projectService, { configuredProjects: 1 }); + checkProjectActualFiles(configuredProjectAt(projectService, 0), [file1.path, file2.path, config.path]); // Check identifiers defined in HTML content are available in .ts file - const project = ts.projectSystem.configuredProjectAt(projectService, 0); + const project = configuredProjectAt(projectService, 0); let completions = project.getLanguageService().getCompletionsAtPosition(file1.path, 1, ts.emptyOptions); assert(completions && ts.some(completions.entries, e => e.name === "hello"), `expected entry hello to be in completion list`); @@ -713,8 +716,8 @@ describe("unittests:: tsserver:: Projects", () => { /*closedFiles*/[file2.path]); // HTML file is still included in project - ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 }); - ts.projectSystem.checkProjectActualFiles(ts.projectSystem.configuredProjectAt(projectService, 0), [file1.path, file2.path, config.path]); + checkNumberOfProjects(projectService, { configuredProjects: 1 }); + checkProjectActualFiles(configuredProjectAt(projectService, 0), [file1.path, file2.path, config.path]); // Check identifiers defined in HTML content are not available in .ts file completions = project.getLanguageService().getCompletionsAtPosition(file1.path, 5, ts.emptyOptions); @@ -737,20 +740,20 @@ describe("unittests:: tsserver:: Projects", () => { content: JSON.stringify({ compilerOptions: { allowJs: true } }) }; - let host = ts.projectSystem.createServerHost([file1, file2, config1, ts.projectSystem.libFile], { executingFilePath: ts.combinePaths(ts.getDirectoryPath(ts.projectSystem.libFile.path), "tsc.js") }); - let session = ts.projectSystem.createSession(host); + let host = createServerHost([file1, file2, config1, libFile], { executingFilePath: ts.combinePaths(ts.getDirectoryPath(libFile.path), "tsc.js") }); + let session = createSession(host); // Specify .html extension as mixed content in a configure host request const extraFileExtensions = [{ extension: ".html", scriptKind: ts.ScriptKind.JS, isMixedContent: true }]; - const configureHostRequest = ts.projectSystem.makeSessionRequest(ts.projectSystem.CommandNames.Configure, { extraFileExtensions }); + const configureHostRequest = makeSessionRequest(ts.server.CommandNames.Configure, { extraFileExtensions }); session.executeCommand(configureHostRequest); - ts.projectSystem.openFilesForSession([file1], session); + openFilesForSession([file1], session); let projectService = session.getProjectService(); - ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 }); + checkNumberOfProjects(projectService, { configuredProjects: 1 }); - let diagnostics = ts.projectSystem.configuredProjectAt(projectService, 0).getLanguageService().getCompilerOptionsDiagnostics(); + let diagnostics = configuredProjectAt(projectService, 0).getLanguageService().getCompilerOptionsDiagnostics(); assert.deepEqual(diagnostics, []); // #2. Ensure no errors when allowJs is false @@ -759,17 +762,17 @@ describe("unittests:: tsserver:: Projects", () => { content: JSON.stringify({ compilerOptions: { allowJs: false } }) }; - host = ts.projectSystem.createServerHost([file1, file2, config2, ts.projectSystem.libFile], { executingFilePath: ts.combinePaths(ts.getDirectoryPath(ts.projectSystem.libFile.path), "tsc.js") }); - session = ts.projectSystem.createSession(host); + host = createServerHost([file1, file2, config2, libFile], { executingFilePath: ts.combinePaths(ts.getDirectoryPath(libFile.path), "tsc.js") }); + session = createSession(host); session.executeCommand(configureHostRequest); - ts.projectSystem.openFilesForSession([file1], session); + openFilesForSession([file1], session); projectService = session.getProjectService(); - ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 }); + checkNumberOfProjects(projectService, { configuredProjects: 1 }); - diagnostics = ts.projectSystem.configuredProjectAt(projectService, 0).getLanguageService().getCompilerOptionsDiagnostics(); + diagnostics = configuredProjectAt(projectService, 0).getLanguageService().getCompilerOptionsDiagnostics(); assert.deepEqual(diagnostics, []); // #3. Ensure no errors when compiler options aren't specified @@ -778,17 +781,17 @@ describe("unittests:: tsserver:: Projects", () => { content: JSON.stringify({}) }; - host = ts.projectSystem.createServerHost([file1, file2, config3, ts.projectSystem.libFile], { executingFilePath: ts.combinePaths(ts.getDirectoryPath(ts.projectSystem.libFile.path), "tsc.js") }); - session = ts.projectSystem.createSession(host); + host = createServerHost([file1, file2, config3, libFile], { executingFilePath: ts.combinePaths(ts.getDirectoryPath(libFile.path), "tsc.js") }); + session = createSession(host); session.executeCommand(configureHostRequest); - ts.projectSystem.openFilesForSession([file1], session); + openFilesForSession([file1], session); projectService = session.getProjectService(); - ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 }); + checkNumberOfProjects(projectService, { configuredProjects: 1 }); - diagnostics = ts.projectSystem.configuredProjectAt(projectService, 0).getLanguageService().getCompilerOptionsDiagnostics(); + diagnostics = configuredProjectAt(projectService, 0).getLanguageService().getCompilerOptionsDiagnostics(); assert.deepEqual(diagnostics, []); // #4. Ensure no errors when files are explicitly specified in tsconfig @@ -797,17 +800,17 @@ describe("unittests:: tsserver:: Projects", () => { content: JSON.stringify({ compilerOptions: { allowJs: true }, files: [file1.path, file2.path] }) }; - host = ts.projectSystem.createServerHost([file1, file2, config4, ts.projectSystem.libFile], { executingFilePath: ts.combinePaths(ts.getDirectoryPath(ts.projectSystem.libFile.path), "tsc.js") }); - session = ts.projectSystem.createSession(host); + host = createServerHost([file1, file2, config4, libFile], { executingFilePath: ts.combinePaths(ts.getDirectoryPath(libFile.path), "tsc.js") }); + session = createSession(host); session.executeCommand(configureHostRequest); - ts.projectSystem.openFilesForSession([file1], session); + openFilesForSession([file1], session); projectService = session.getProjectService(); - ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 }); + checkNumberOfProjects(projectService, { configuredProjects: 1 }); - diagnostics = ts.projectSystem.configuredProjectAt(projectService, 0).getLanguageService().getCompilerOptionsDiagnostics(); + diagnostics = configuredProjectAt(projectService, 0).getLanguageService().getCompilerOptionsDiagnostics(); assert.deepEqual(diagnostics, []); // #4. Ensure no errors when files are explicitly excluded in tsconfig @@ -816,17 +819,17 @@ describe("unittests:: tsserver:: Projects", () => { content: JSON.stringify({ compilerOptions: { allowJs: true }, exclude: [file2.path] }) }; - host = ts.projectSystem.createServerHost([file1, file2, config5, ts.projectSystem.libFile], { executingFilePath: ts.combinePaths(ts.getDirectoryPath(ts.projectSystem.libFile.path), "tsc.js") }); - session = ts.projectSystem.createSession(host); + host = createServerHost([file1, file2, config5, libFile], { executingFilePath: ts.combinePaths(ts.getDirectoryPath(libFile.path), "tsc.js") }); + session = createSession(host); session.executeCommand(configureHostRequest); - ts.projectSystem.openFilesForSession([file1], session); + openFilesForSession([file1], session); projectService = session.getProjectService(); - ts.projectSystem.checkNumberOfProjects(projectService, { configuredProjects: 1 }); + checkNumberOfProjects(projectService, { configuredProjects: 1 }); - diagnostics = ts.projectSystem.configuredProjectAt(projectService, 0).getLanguageService().getCompilerOptionsDiagnostics(); + diagnostics = configuredProjectAt(projectService, 0).getLanguageService().getCompilerOptionsDiagnostics(); assert.deepEqual(diagnostics, []); }); @@ -839,21 +842,21 @@ describe("unittests:: tsserver:: Projects", () => { path: "/a/b/f2.ts", content: "export let x = 1" }; - const host = ts.projectSystem.createServerHost([file1, file2]); - const projectService = ts.projectSystem.createProjectService(host); + const host = createServerHost([file1, file2]); + const projectService = createProjectService(host); projectService.openClientFile(file1.path); projectService.openClientFile(file2.path); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 1 }); + checkNumberOfProjects(projectService, { inferredProjects: 1 }); projectService.applyChangesInOpenFiles( /*openFiles*/ undefined, /*changedFiles*/ts.singleIterator({ fileName: file1.path, changes: ts.singleIterator({ span: ts.createTextSpan(0, file1.path.length), newText: "let y = 1" }) }), /*closedFiles*/ undefined); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 1 }); + checkNumberOfProjects(projectService, { inferredProjects: 1 }); projectService.ensureInferredProjectsUpToDate_TestOnly(); - ts.projectSystem.checkNumberOfProjects(projectService, { inferredProjects: 2 }); + checkNumberOfProjects(projectService, { inferredProjects: 2 }); }); it("files with mixed content are handled correctly", () => { @@ -861,8 +864,8 @@ describe("unittests:: tsserver:: Projects", () => { path: "/a/b/f1.html", content: `