From 281f16984f30aece5704987ad27643f920992f9c Mon Sep 17 00:00:00 2001 From: Andrew Bradley Date: Sat, 19 Feb 2022 00:00:11 -0500 Subject: [PATCH 1/3] fix --- src/resolver-functions.ts | 87 +++++++++++++++++++++++---------------- src/ts-compiler-types.ts | 47 ++++++++++++++++++++- 2 files changed, 96 insertions(+), 38 deletions(-) diff --git a/src/resolver-functions.ts b/src/resolver-functions.ts index f032bf0a8..3e8d7ffff 100644 --- a/src/resolver-functions.ts +++ b/src/resolver-functions.ts @@ -1,5 +1,5 @@ import { resolve } from 'path'; -import type * as _ts from 'typescript'; +import type { TSCommon, TSInternal } from './ts-compiler-types'; import type { ProjectLocalResolveHelper } from './util'; /** @@ -7,11 +7,11 @@ import type { ProjectLocalResolveHelper } from './util'; * In a factory because these are shared across both CompilerHost and LanguageService codepaths */ export function createResolverFunctions(kwargs: { - ts: typeof _ts; - host: _ts.ModuleResolutionHost; + ts: TSCommon & TSInternal; + host: TSCommon.ModuleResolutionHost; cwd: string; getCanonicalFileName: (filename: string) => string; - config: _ts.ParsedCommandLine; + config: TSCommon.ParsedCommandLine; projectLocalResolveHelper: ProjectLocalResolveHelper; }) { const { @@ -58,7 +58,9 @@ export function createResolverFunctions(kwargs: { * If we need to emit JS for a file, force TS to consider it non-external */ const fixupResolvedModule = ( - resolvedModule: _ts.ResolvedModule | _ts.ResolvedTypeReferenceDirective + resolvedModule: + | TSCommon.ResolvedModule + | TSCommon.ResolvedTypeReferenceDirective ) => { const { resolvedFileName } = resolvedModule; if (resolvedFileName === undefined) return; @@ -82,35 +84,36 @@ export function createResolverFunctions(kwargs: { * Older ts versions do not pass `redirectedReference` nor `options`. * We must pass `redirectedReference` to newer ts versions, but cannot rely on `options`, hence the weird argument name */ - const resolveModuleNames: _ts.LanguageServiceHost['resolveModuleNames'] = ( - moduleNames: string[], - containingFile: string, - reusedNames: string[] | undefined, - redirectedReference: _ts.ResolvedProjectReference | undefined, - optionsOnlyWithNewerTsVersions: _ts.CompilerOptions - ): (_ts.ResolvedModule | undefined)[] => { - return moduleNames.map((moduleName) => { - const { resolvedModule } = ts.resolveModuleName( - moduleName, - containingFile, - config.options, - host, - moduleResolutionCache, - redirectedReference - ); - if (resolvedModule) { - fixupResolvedModule(resolvedModule); - } - return resolvedModule; - }); - }; + const resolveModuleNames: TSCommon.LanguageServiceHost['resolveModuleNames'] = + ( + moduleNames: string[], + containingFile: string, + reusedNames: string[] | undefined, + redirectedReference: TSCommon.ResolvedProjectReference | undefined, + optionsOnlyWithNewerTsVersions: TSCommon.CompilerOptions + ): (TSCommon.ResolvedModule | undefined)[] => { + return moduleNames.map((moduleName) => { + const { resolvedModule } = ts.resolveModuleName( + moduleName, + containingFile, + config.options, + host, + moduleResolutionCache, + redirectedReference + ); + if (resolvedModule) { + fixupResolvedModule(resolvedModule); + } + return resolvedModule; + }); + }; // language service never calls this, but TS docs recommend that we implement it - const getResolvedModuleWithFailedLookupLocationsFromCache: _ts.LanguageServiceHost['getResolvedModuleWithFailedLookupLocationsFromCache'] = + const getResolvedModuleWithFailedLookupLocationsFromCache: TSCommon.LanguageServiceHost['getResolvedModuleWithFailedLookupLocationsFromCache'] = ( moduleName, containingFile - ): _ts.ResolvedModuleWithFailedLookupLocations | undefined => { + ): TSCommon.ResolvedModuleWithFailedLookupLocations | undefined => { const ret = ts.resolveModuleNameFromCache( moduleName, containingFile, @@ -122,22 +125,34 @@ export function createResolverFunctions(kwargs: { return ret; }; - const resolveTypeReferenceDirectives: _ts.LanguageServiceHost['resolveTypeReferenceDirectives'] = + const resolveTypeReferenceDirectives: TSCommon.LanguageServiceHost['resolveTypeReferenceDirectives'] = ( - typeDirectiveNames: string[], + typeDirectiveNames: string[] | readonly TSCommon.FileReference[], containingFile: string, - redirectedReference: _ts.ResolvedProjectReference | undefined, - options: _ts.CompilerOptions - ): (_ts.ResolvedTypeReferenceDirective | undefined)[] => { + redirectedReference: TSCommon.ResolvedProjectReference | undefined, + options: TSCommon.CompilerOptions, + containingFileMode?: TSCommon.SourceFile['impliedNodeFormat'] | undefined // new impliedNodeFormat is accepted by compilerHost + ): (TSCommon.ResolvedTypeReferenceDirective | undefined)[] => { // Note: seems to be called with empty typeDirectiveNames array for all files. + // TODO consider using `ts.loadWithTypeDirectiveCache` return typeDirectiveNames.map((typeDirectiveName) => { + // Copy-pasted from TS source: + const nameIsString = typeof typeDirectiveName === 'string'; + const mode = nameIsString + ? undefined + : ts.getModeForFileReference!(typeDirectiveName, containingFileMode); + const strName = nameIsString + ? typeDirectiveName + : typeDirectiveName.fileName.toLowerCase(); let { resolvedTypeReferenceDirective } = ts.resolveTypeReferenceDirective( - typeDirectiveName, + strName, containingFile, config.options, host, - redirectedReference + redirectedReference, + undefined, + mode ); if (typeDirectiveName === 'node' && !resolvedTypeReferenceDirective) { // Resolve @types/node relative to project first, then __dirname (copy logic from elsewhere / refactor into reusable function) diff --git a/src/ts-compiler-types.ts b/src/ts-compiler-types.ts index b17111c3a..0abaaec21 100644 --- a/src/ts-compiler-types.ts +++ b/src/ts-compiler-types.ts @@ -1,7 +1,13 @@ import type * as _ts from 'typescript'; /** - * Common TypeScript interfaces between versions. + * Common TypeScript interfaces between versions. We endeavour to write ts-node's own code against these types instead + * of against `import "typescript"`, though we are not yet doing this consistently. + * + * Sometimes typescript@next adds an API we need to use. But we build ts-node against typescript@latest. + * In these cases, we must declare that API explicitly here. Our declarations include the newer typescript@next APIs. + * Importantly, these re-declarations are *not* TypeScript internals. They are public APIs that only exist in + * pre-release versions of typescript. */ export interface TSCommon { version: typeof _ts.version; @@ -26,7 +32,16 @@ export interface TSCommon { createModuleResolutionCache: typeof _ts.createModuleResolutionCache; resolveModuleName: typeof _ts.resolveModuleName; resolveModuleNameFromCache: typeof _ts.resolveModuleNameFromCache; - resolveTypeReferenceDirective: typeof _ts.resolveTypeReferenceDirective; + // Changed in TS 4.7 + resolveTypeReferenceDirective( + typeReferenceDirectiveName: string, + containingFile: string | undefined, + options: _ts.CompilerOptions, + host: _ts.ModuleResolutionHost, + redirectedReference?: _ts.ResolvedProjectReference, + cache?: _ts.TypeReferenceDirectiveResolutionCache, + resolutionMode?: _ts.SourceFile['impliedNodeFormat'] + ): _ts.ResolvedTypeReferenceDirectiveWithFailedLookupLocations; createIncrementalCompilerHost: typeof _ts.createIncrementalCompilerHost; createSourceFile: typeof _ts.createSourceFile; getDefaultLibFileName: typeof _ts.getDefaultLibFileName; @@ -36,6 +51,29 @@ export interface TSCommon { Extension: typeof _ts.Extension; ModuleResolutionKind: typeof _ts.ModuleResolutionKind; } +export namespace TSCommon { + export interface LanguageServiceHost extends _ts.LanguageServiceHost { + // Modified in 4.7 + resolveTypeReferenceDirectives?( + typeDirectiveNames: string[] | _ts.FileReference[], + containingFile: string, + redirectedReference: _ts.ResolvedProjectReference | undefined, + options: _ts.CompilerOptions, + containingFileMode?: _ts.SourceFile['impliedNodeFormat'] | undefined + ): (_ts.ResolvedTypeReferenceDirective | undefined)[]; + } + export type ModuleResolutionHost = _ts.ModuleResolutionHost; + export type ParsedCommandLine = _ts.ParsedCommandLine; + export type ResolvedModule = _ts.ResolvedModule; + export type ResolvedTypeReferenceDirective = + _ts.ResolvedTypeReferenceDirective; + export type CompilerOptions = _ts.CompilerOptions; + export type ResolvedProjectReference = _ts.ResolvedProjectReference; + export type ResolvedModuleWithFailedLookupLocations = + _ts.ResolvedModuleWithFailedLookupLocations; + export type FileReference = _ts.FileReference; + export type SourceFile = _ts.SourceFile; +} /** * Compiler APIs we use that are marked internal and not included in TypeScript's public API declarations @@ -69,6 +107,11 @@ export interface TSInternal { redirectedReference?: _ts.ResolvedProjectReference, lookupConfig?: boolean ): _ts.ResolvedModuleWithFailedLookupLocations; + // Added in TS 4.7 + getModeForFileReference?: ( + ref: _ts.FileReference | string, + containingFileMode: _ts.SourceFile['impliedNodeFormat'] + ) => _ts.SourceFile['impliedNodeFormat']; } /** @internal */ export namespace TSInternal { From 6d7230dbb83e964aefcd0642c1f3723ad3d1c0ff Mon Sep 17 00:00:00 2001 From: Andrew Bradley Date: Sat, 19 Feb 2022 00:13:41 -0500 Subject: [PATCH 2/3] Fix --- src/index.ts | 2 +- src/resolver-functions.ts | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/index.ts b/src/index.ts index 0ffeea3fc..0544b2d98 100644 --- a/src/index.ts +++ b/src/index.ts @@ -605,7 +605,7 @@ export function create(rawOptions: CreateOptions = {}): Service { const projectLocalResolveHelper = createProjectLocalResolveHelper(relativeToPath); const compiler = projectLocalResolveHelper(name || 'typescript', true); - const ts: typeof _ts = attemptRequireWithV8CompileCache(require, compiler); + const ts: TSCommon = attemptRequireWithV8CompileCache(require, compiler); return { compiler, ts, projectLocalResolveHelper }; } diff --git a/src/resolver-functions.ts b/src/resolver-functions.ts index 3e8d7ffff..ecb5d98e2 100644 --- a/src/resolver-functions.ts +++ b/src/resolver-functions.ts @@ -7,7 +7,7 @@ import type { ProjectLocalResolveHelper } from './util'; * In a factory because these are shared across both CompilerHost and LanguageService codepaths */ export function createResolverFunctions(kwargs: { - ts: TSCommon & TSInternal; + ts: TSCommon; host: TSCommon.ModuleResolutionHost; cwd: string; getCanonicalFileName: (filename: string) => string; @@ -140,7 +140,10 @@ export function createResolverFunctions(kwargs: { const nameIsString = typeof typeDirectiveName === 'string'; const mode = nameIsString ? undefined - : ts.getModeForFileReference!(typeDirectiveName, containingFileMode); + : (ts as any as TSInternal).getModeForFileReference!( + typeDirectiveName, + containingFileMode + ); const strName = nameIsString ? typeDirectiveName : typeDirectiveName.fileName.toLowerCase(); From 9f789d0d91c6eba30ac7f7aad45194a23b44f159 Mon Sep 17 00:00:00 2001 From: Andrew Bradley Date: Sat, 19 Feb 2022 00:16:37 -0500 Subject: [PATCH 3/3] fix --- package-lock.json | 85 +++++++++++++++++------------------------------ package.json | 4 +-- 2 files changed, 32 insertions(+), 57 deletions(-) diff --git a/package-lock.json b/package-lock.json index 632b7c965..9147467b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3016,15 +3016,6 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, - "json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "dev": true, - "requires": { - "jsonify": "~0.0.0" - } - }, "json5": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", @@ -3040,12 +3031,6 @@ "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", "dev": true }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", - "dev": true - }, "keyv": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", @@ -4206,6 +4191,12 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, + "safe-stable-stringify": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.3.1.tgz", + "integrity": "sha512-kYBSfT+troD9cDA85VDnHZ1rpHC50O0g1e6WlGHVCz/g+JS+9WKLj+XwFYyR8UbrZN8ll9HUpDAAddY58MGisg==", + "dev": true + }, "semver": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.1.3.tgz", @@ -4648,12 +4639,12 @@ "dev": true }, "ts-node": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.2.1.tgz", - "integrity": "sha512-hCnyOyuGmD5wHleOQX6NIjJtYVIO8bPP8F2acWkB4W06wdlkgyvJtubO/I9NkI88hCFECbsEgoLc0VNkYmcSfw==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.5.0.tgz", + "integrity": "sha512-6kEJKwVxAJ35W4akuiysfKwKmjkbYxwQMTBaAxo9KKAx/Yd26mPUyhGz3ji+EsJoAgrLqVsYHNuuYwQe22lbtw==", "dev": true, "requires": { - "@cspotcode/source-map-support": "0.6.1", + "@cspotcode/source-map-support": "0.7.0", "@tsconfig/node10": "^1.0.7", "@tsconfig/node12": "^1.0.7", "@tsconfig/node14": "^1.0.0", @@ -4664,18 +4655,8 @@ "create-require": "^1.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.0", "yn": "3.1.1" - }, - "dependencies": { - "@cspotcode/source-map-support": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.6.1.tgz", - "integrity": "sha512-DX3Z+T5dt1ockmPdobJS/FAsQPW4V4SrWEhD2iYQT2Cb2tQsiMnYxrcUH9By/Z3B+v0S5LMBkQtV/XOBbpLEOg==", - "dev": true, - "requires": { - "@cspotcode/source-map-consumer": "0.8.0" - } - } } }, "tslib": { @@ -4735,30 +4716,30 @@ } }, "typescript": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz", - "integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==", + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", + "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", "dev": true }, "typescript-json-schema": { - "version": "0.51.0", - "resolved": "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.51.0.tgz", - "integrity": "sha512-POhWbUNs2oaBti1W9k/JwS+uDsaZD9J/KQiZ/iXRQEOD0lTn9VmshIls9tn+A9X6O+smPjeEz5NEy6WTkCCzrQ==", + "version": "0.53.0", + "resolved": "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.53.0.tgz", + "integrity": "sha512-BcFxC9nipQQOXxrBGI/jOWU31BwzVh6vqJR008G8VHKJtQ8YrZX6veriXfTK1l+L0/ff0yKl3mZigMLA6ZqkHg==", "dev": true, "requires": { "@types/json-schema": "^7.0.9", "@types/node": "^16.9.2", "glob": "^7.1.7", - "json-stable-stringify": "^1.0.1", + "safe-stable-stringify": "^2.2.0", "ts-node": "^10.2.1", - "typescript": "~4.2.3", + "typescript": "~4.5.0", "yargs": "^17.1.1" }, "dependencies": { "@types/node": { - "version": "16.10.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.10.1.tgz", - "integrity": "sha512-4/Z9DMPKFexZj/Gn3LylFgamNKHm4K3QDi0gz9B26Uk0c8izYf97B5fxfpspMNkWlFupblKM/nV8+NA9Ffvr+w==", + "version": "16.11.25", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.25.tgz", + "integrity": "sha512-NrTwfD7L1RTc2qrHQD4RTTy4p0CO2LatKBEKEds3CaVuhoM/+DJzmWZl5f+ikR8cm8F5mfJxK+9rQq07gRiSjQ==", "dev": true }, "glob": { @@ -4774,12 +4755,6 @@ "once": "^1.3.0", "path-is-absolute": "^1.0.0" } - }, - "typescript": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", - "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==", - "dev": true } } }, @@ -5047,18 +5022,18 @@ "dev": true }, "yargs": { - "version": "17.2.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.2.1.tgz", - "integrity": "sha512-XfR8du6ua4K6uLGm5S6fA+FIJom/MdJcFNVY8geLlp2v8GYbOXD4EB1tPNZsRn4vBzKGMgb5DRZMeWuFc2GO8Q==", + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz", + "integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==", "dev": true, "requires": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.0.0" }, "dependencies": { "y18n": { @@ -5070,9 +5045,9 @@ } }, "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA==", "dev": true }, "yn": { diff --git a/package.json b/package.json index 5e6323f45..9e8bbdb61 100644 --- a/package.json +++ b/package.json @@ -134,8 +134,8 @@ "semver": "^7.1.3", "throat": "^6.0.1", "typedoc": "^0.22.10", - "typescript": "4.5.2", - "typescript-json-schema": "^0.51.0", + "typescript": "4.5.5", + "typescript-json-schema": "^0.53.0", "util.promisify": "^1.0.1" }, "peerDependencies": {