From a45df09a4de3c84ef777ea08564a5f4f986b7c3f Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 6 Aug 2020 17:05:28 +0000 Subject: [PATCH 1/2] Cherry-pick PR #39937 into release-4.0 Component commits: 0b9b321b0c Handle empty package.json files --- src/server/editorServices.ts | 15 +++++++-------- src/server/packageJsonCache.ts | 8 +++----- src/services/utilities.ts | 4 +--- .../unittests/tsserver/packageJsonInfo.ts | 17 +++++++++++++++++ 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index b4de59a455ccb..28c49a8d4609c 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -3774,12 +3774,10 @@ namespace ts.server { /*@internal*/ getPackageJsonsVisibleToFile(fileName: string, rootDir?: string): readonly PackageJsonInfo[] { const packageJsonCache = this.packageJsonCache; - const watchPackageJsonFile = this.watchPackageJsonFile.bind(this); - const toPath = this.toPath.bind(this); - const rootPath = rootDir && toPath(rootDir); - const filePath = toPath(fileName); + const rootPath = rootDir && this.toPath(rootDir); + const filePath = this.toPath(fileName); const result: PackageJsonInfo[] = []; - forEachAncestorDirectory(getDirectoryPath(filePath), function processDirectory(directory): boolean | undefined { + const processDirectory = (directory: Path): boolean | undefined => { switch (packageJsonCache.directoryHasPackageJson(directory)) { // Sync and check same directory again case Ternary.Maybe: @@ -3788,15 +3786,16 @@ namespace ts.server { // Check package.json case Ternary.True: const packageJsonFileName = combinePaths(directory, "package.json"); - watchPackageJsonFile(packageJsonFileName); + this.watchPackageJsonFile(packageJsonFileName as Path); const info = packageJsonCache.getInDirectory(directory); if (info) result.push(info); } - if (rootPath && rootPath === toPath(directory)) { + if (rootPath && rootPath === this.toPath(directory)) { return true; } - }); + }; + forEachAncestorDirectory(getDirectoryPath(filePath), processDirectory); return result; } diff --git a/src/server/packageJsonCache.ts b/src/server/packageJsonCache.ts index 8c09ebda2c4d6..3aa6129430a53 100644 --- a/src/server/packageJsonCache.ts +++ b/src/server/packageJsonCache.ts @@ -42,11 +42,9 @@ namespace ts.server { }; function addOrUpdate(fileName: Path) { - const packageJsonInfo = createPackageJsonInfo(fileName, host.host); - if (packageJsonInfo !== undefined) { - packageJsons.set(fileName, packageJsonInfo); - directoriesWithoutPackageJson.delete(getDirectoryPath(fileName)); - } + const packageJsonInfo = Debug.checkDefined(createPackageJsonInfo(fileName, host.host)); + packageJsons.set(fileName, packageJsonInfo); + directoriesWithoutPackageJson.delete(getDirectoryPath(fileName)); } function directoryHasPackageJson(directory: Path) { diff --git a/src/services/utilities.ts b/src/services/utilities.ts index c11c65d076dd6..baa70bf1df84f 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -2735,9 +2735,7 @@ namespace ts { type PackageJsonRaw = Record | undefined>; const dependencyKeys = ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"] as const; - const stringContent = host.readFile(fileName); - if (!stringContent) return undefined; - + const stringContent = host.readFile(fileName) || ""; const content = tryParseJson(stringContent) as PackageJsonRaw | undefined; const info: Pick = {}; if (content) { diff --git a/src/testRunner/unittests/tsserver/packageJsonInfo.ts b/src/testRunner/unittests/tsserver/packageJsonInfo.ts index efc977a335c92..b931d984c1275 100644 --- a/src/testRunner/unittests/tsserver/packageJsonInfo.ts +++ b/src/testRunner/unittests/tsserver/packageJsonInfo.ts @@ -82,6 +82,23 @@ namespace ts.projectSystem { assert.ok(packageJsonInfo2.peerDependencies); assert.ok(packageJsonInfo2.optionalDependencies); }); + + it("handles empty package.json", () => { + const packageJsonContent = ""; + const { projectService, host } = setup([tsConfig, { path: packageJson.path, content: packageJsonContent }]); + projectService.getPackageJsonsVisibleToFile("/src/whatever/blah.ts" as Path); + const packageJsonInfo = projectService.packageJsonCache.getInDirectory("/" as Path)!; + assert.isFalse(packageJsonInfo.parseable); + + host.writeFile(packageJson.path, packageJson.content); + projectService.getPackageJsonsVisibleToFile("/src/whatever/blah.ts" as Path); + const packageJsonInfo2 = projectService.packageJsonCache.getInDirectory("/" as Path)!; + assert.ok(packageJsonInfo2); + assert.ok(packageJsonInfo2.dependencies); + assert.ok(packageJsonInfo2.devDependencies); + assert.ok(packageJsonInfo2.peerDependencies); + assert.ok(packageJsonInfo2.optionalDependencies); + }); }); function setup(files: readonly File[] = [tsConfig, packageJson]) { From fcc28d7dcca65a4b4480198745571a0be784a12a Mon Sep 17 00:00:00 2001 From: typescript-bot Date: Thu, 6 Aug 2020 17:06:58 +0000 Subject: [PATCH 2/2] Update LKG --- lib/tsc.js | 2 ++ lib/tsserver.js | 30 ++++++++++++++---------------- lib/tsserverlibrary.js | 30 ++++++++++++++---------------- lib/typescript.js | 6 +++--- lib/typescriptServices.js | 6 +++--- lib/typingsInstaller.js | 2 ++ 6 files changed, 38 insertions(+), 38 deletions(-) diff --git a/lib/tsc.js b/lib/tsc.js index 8ed94814ec513..7200b8d96b41d 100644 --- a/lib/tsc.js +++ b/lib/tsc.js @@ -20154,11 +20154,13 @@ var ts; }; ts.classPrivateFieldGetHelper = { name: "typescript:classPrivateFieldGet", + importName: "__classPrivateFieldGet", scoped: false, text: "\n var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, privateMap) {\n if (!privateMap.has(receiver)) {\n throw new TypeError(\"attempted to get private field on non-instance\");\n }\n return privateMap.get(receiver);\n };" }; ts.classPrivateFieldSetHelper = { name: "typescript:classPrivateFieldSet", + importName: "__classPrivateFieldSet", scoped: false, text: "\n var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, privateMap, value) {\n if (!privateMap.has(receiver)) {\n throw new TypeError(\"attempted to set private field on non-instance\");\n }\n privateMap.set(receiver, value);\n return value;\n };" }; diff --git a/lib/tsserver.js b/lib/tsserver.js index bfd698200569c..bd1dce97016bf 100644 --- a/lib/tsserver.js +++ b/lib/tsserver.js @@ -25223,11 +25223,13 @@ var ts; // Class fields helpers ts.classPrivateFieldGetHelper = { name: "typescript:classPrivateFieldGet", + importName: "__classPrivateFieldGet", scoped: false, text: "\n var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, privateMap) {\n if (!privateMap.has(receiver)) {\n throw new TypeError(\"attempted to get private field on non-instance\");\n }\n return privateMap.get(receiver);\n };" }; ts.classPrivateFieldSetHelper = { name: "typescript:classPrivateFieldSet", + importName: "__classPrivateFieldSet", scoped: false, text: "\n var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, privateMap, value) {\n if (!privateMap.has(receiver)) {\n throw new TypeError(\"attempted to set private field on non-instance\");\n }\n privateMap.set(receiver, value);\n return value;\n };" }; @@ -113237,9 +113239,7 @@ var ts; return undefined; } var dependencyKeys = ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"]; - var stringContent = host.readFile(fileName); - if (!stringContent) - return undefined; + var stringContent = host.readFile(fileName) || ""; var content = tryParseJson(stringContent); var info = {}; if (content) { @@ -152444,13 +152444,12 @@ var ts; }; /*@internal*/ ProjectService.prototype.getPackageJsonsVisibleToFile = function (fileName, rootDir) { + var _this = this; var packageJsonCache = this.packageJsonCache; - var watchPackageJsonFile = this.watchPackageJsonFile.bind(this); - var toPath = this.toPath.bind(this); - var rootPath = rootDir && toPath(rootDir); - var filePath = toPath(fileName); + var rootPath = rootDir && this.toPath(rootDir); + var filePath = this.toPath(fileName); var result = []; - ts.forEachAncestorDirectory(ts.getDirectoryPath(filePath), function processDirectory(directory) { + var processDirectory = function (directory) { switch (packageJsonCache.directoryHasPackageJson(directory)) { // Sync and check same directory again case 1 /* Maybe */: @@ -152459,15 +152458,16 @@ var ts; // Check package.json case -1 /* True */: var packageJsonFileName = ts.combinePaths(directory, "package.json"); - watchPackageJsonFile(packageJsonFileName); + _this.watchPackageJsonFile(packageJsonFileName); var info = packageJsonCache.getInDirectory(directory); if (info) result.push(info); } - if (rootPath && rootPath === toPath(directory)) { + if (rootPath && rootPath === _this.toPath(directory)) { return true; } - }); + }; + ts.forEachAncestorDirectory(ts.getDirectoryPath(filePath), processDirectory); return result; }; /*@internal*/ @@ -152572,11 +152572,9 @@ var ts; }, }; function addOrUpdate(fileName) { - var packageJsonInfo = ts.createPackageJsonInfo(fileName, host.host); - if (packageJsonInfo !== undefined) { - packageJsons.set(fileName, packageJsonInfo); - directoriesWithoutPackageJson.delete(ts.getDirectoryPath(fileName)); - } + var packageJsonInfo = ts.Debug.checkDefined(ts.createPackageJsonInfo(fileName, host.host)); + packageJsons.set(fileName, packageJsonInfo); + directoriesWithoutPackageJson.delete(ts.getDirectoryPath(fileName)); } function directoryHasPackageJson(directory) { return packageJsons.has(ts.combinePaths(directory, "package.json")) ? -1 /* True */ : diff --git a/lib/tsserverlibrary.js b/lib/tsserverlibrary.js index d6f6c58d7c8ba..e3e146ce3862c 100644 --- a/lib/tsserverlibrary.js +++ b/lib/tsserverlibrary.js @@ -25417,11 +25417,13 @@ var ts; // Class fields helpers ts.classPrivateFieldGetHelper = { name: "typescript:classPrivateFieldGet", + importName: "__classPrivateFieldGet", scoped: false, text: "\n var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, privateMap) {\n if (!privateMap.has(receiver)) {\n throw new TypeError(\"attempted to get private field on non-instance\");\n }\n return privateMap.get(receiver);\n };" }; ts.classPrivateFieldSetHelper = { name: "typescript:classPrivateFieldSet", + importName: "__classPrivateFieldSet", scoped: false, text: "\n var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, privateMap, value) {\n if (!privateMap.has(receiver)) {\n throw new TypeError(\"attempted to set private field on non-instance\");\n }\n privateMap.set(receiver, value);\n return value;\n };" }; @@ -113804,9 +113806,7 @@ var ts; return undefined; } var dependencyKeys = ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"]; - var stringContent = host.readFile(fileName); - if (!stringContent) - return undefined; + var stringContent = host.readFile(fileName) || ""; var content = tryParseJson(stringContent); var info = {}; if (content) { @@ -152638,13 +152638,12 @@ var ts; }; /*@internal*/ ProjectService.prototype.getPackageJsonsVisibleToFile = function (fileName, rootDir) { + var _this = this; var packageJsonCache = this.packageJsonCache; - var watchPackageJsonFile = this.watchPackageJsonFile.bind(this); - var toPath = this.toPath.bind(this); - var rootPath = rootDir && toPath(rootDir); - var filePath = toPath(fileName); + var rootPath = rootDir && this.toPath(rootDir); + var filePath = this.toPath(fileName); var result = []; - ts.forEachAncestorDirectory(ts.getDirectoryPath(filePath), function processDirectory(directory) { + var processDirectory = function (directory) { switch (packageJsonCache.directoryHasPackageJson(directory)) { // Sync and check same directory again case 1 /* Maybe */: @@ -152653,15 +152652,16 @@ var ts; // Check package.json case -1 /* True */: var packageJsonFileName = ts.combinePaths(directory, "package.json"); - watchPackageJsonFile(packageJsonFileName); + _this.watchPackageJsonFile(packageJsonFileName); var info = packageJsonCache.getInDirectory(directory); if (info) result.push(info); } - if (rootPath && rootPath === toPath(directory)) { + if (rootPath && rootPath === _this.toPath(directory)) { return true; } - }); + }; + ts.forEachAncestorDirectory(ts.getDirectoryPath(filePath), processDirectory); return result; }; /*@internal*/ @@ -152766,11 +152766,9 @@ var ts; }, }; function addOrUpdate(fileName) { - var packageJsonInfo = ts.createPackageJsonInfo(fileName, host.host); - if (packageJsonInfo !== undefined) { - packageJsons.set(fileName, packageJsonInfo); - directoriesWithoutPackageJson.delete(ts.getDirectoryPath(fileName)); - } + var packageJsonInfo = ts.Debug.checkDefined(ts.createPackageJsonInfo(fileName, host.host)); + packageJsons.set(fileName, packageJsonInfo); + directoriesWithoutPackageJson.delete(ts.getDirectoryPath(fileName)); } function directoryHasPackageJson(directory) { return packageJsons.has(ts.combinePaths(directory, "package.json")) ? -1 /* True */ : diff --git a/lib/typescript.js b/lib/typescript.js index 33f97e22015a6..ac09d5cd5aff9 100644 --- a/lib/typescript.js +++ b/lib/typescript.js @@ -25417,11 +25417,13 @@ var ts; // Class fields helpers ts.classPrivateFieldGetHelper = { name: "typescript:classPrivateFieldGet", + importName: "__classPrivateFieldGet", scoped: false, text: "\n var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, privateMap) {\n if (!privateMap.has(receiver)) {\n throw new TypeError(\"attempted to get private field on non-instance\");\n }\n return privateMap.get(receiver);\n };" }; ts.classPrivateFieldSetHelper = { name: "typescript:classPrivateFieldSet", + importName: "__classPrivateFieldSet", scoped: false, text: "\n var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, privateMap, value) {\n if (!privateMap.has(receiver)) {\n throw new TypeError(\"attempted to set private field on non-instance\");\n }\n privateMap.set(receiver, value);\n return value;\n };" }; @@ -113804,9 +113806,7 @@ var ts; return undefined; } var dependencyKeys = ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"]; - var stringContent = host.readFile(fileName); - if (!stringContent) - return undefined; + var stringContent = host.readFile(fileName) || ""; var content = tryParseJson(stringContent); var info = {}; if (content) { diff --git a/lib/typescriptServices.js b/lib/typescriptServices.js index 2e37c57101542..efaa2e24d16b2 100644 --- a/lib/typescriptServices.js +++ b/lib/typescriptServices.js @@ -25417,11 +25417,13 @@ var ts; // Class fields helpers ts.classPrivateFieldGetHelper = { name: "typescript:classPrivateFieldGet", + importName: "__classPrivateFieldGet", scoped: false, text: "\n var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, privateMap) {\n if (!privateMap.has(receiver)) {\n throw new TypeError(\"attempted to get private field on non-instance\");\n }\n return privateMap.get(receiver);\n };" }; ts.classPrivateFieldSetHelper = { name: "typescript:classPrivateFieldSet", + importName: "__classPrivateFieldSet", scoped: false, text: "\n var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, privateMap, value) {\n if (!privateMap.has(receiver)) {\n throw new TypeError(\"attempted to set private field on non-instance\");\n }\n privateMap.set(receiver, value);\n return value;\n };" }; @@ -113804,9 +113806,7 @@ var ts; return undefined; } var dependencyKeys = ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"]; - var stringContent = host.readFile(fileName); - if (!stringContent) - return undefined; + var stringContent = host.readFile(fileName) || ""; var content = tryParseJson(stringContent); var info = {}; if (content) { diff --git a/lib/typingsInstaller.js b/lib/typingsInstaller.js index e3bd36acb1390..0ae3053bfd623 100644 --- a/lib/typingsInstaller.js +++ b/lib/typingsInstaller.js @@ -25212,11 +25212,13 @@ var ts; // Class fields helpers ts.classPrivateFieldGetHelper = { name: "typescript:classPrivateFieldGet", + importName: "__classPrivateFieldGet", scoped: false, text: "\n var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, privateMap) {\n if (!privateMap.has(receiver)) {\n throw new TypeError(\"attempted to get private field on non-instance\");\n }\n return privateMap.get(receiver);\n };" }; ts.classPrivateFieldSetHelper = { name: "typescript:classPrivateFieldSet", + importName: "__classPrivateFieldSet", scoped: false, text: "\n var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, privateMap, value) {\n if (!privateMap.has(receiver)) {\n throw new TypeError(\"attempted to set private field on non-instance\");\n }\n privateMap.set(receiver, value);\n return value;\n };" };