From 02722ee44ede29dabbe190b95a91be702416c7a7 Mon Sep 17 00:00:00 2001 From: Ahn Date: Wed, 22 Apr 2020 19:01:38 +0200 Subject: [PATCH] chore: release 25.5.0-alpha.0 --- appveyor.yml | 48 --------- .../__snapshots__/logger.test.ts.snap | 12 +-- package.json | 2 +- src/__helpers__/fakers.ts | 2 + src/compiler/compiler-utils.spec.ts | 67 ------------ src/compiler/compiler-utils.ts | 9 +- src/compiler/instance.ts | 100 +++++++++--------- src/compiler/language-service.spec.ts | 18 ++-- src/compiler/language-service.ts | 90 +++++++++------- src/compiler/transpiler.spec.ts | 14 ++- src/compiler/transpiler.ts | 27 ++--- src/config/config-set.spec.ts | 6 +- src/types.ts | 4 +- 13 files changed, 147 insertions(+), 252 deletions(-) delete mode 100644 appveyor.yml delete mode 100644 src/compiler/compiler-utils.spec.ts diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index f99c0e7ad8..0000000000 --- a/appveyor.yml +++ /dev/null @@ -1,48 +0,0 @@ -# http://www.appveyor.com/docs/appveyor-yml -version: '{build}' -pull_requests: - do_not_increment_build_number: true -skip_tags: true -shallow_clone: true -build: off -deploy: off -platform: x64 -branches: - except: - - gh-pages - -# clear the cache if commit contains given text -init: -- ps: IF ($env:APPVEYOR_REPO_COMMIT_MESSAGE -Match "\[clean ci-cache\]" ) {$env:APPVEYOR_CACHE_SKIP_RESTORE = "true"} -- ps: IF ($env:APPVEYOR_REPO_COMMIT_MESSAGE_EXTENDED -Match "\[clean ci-cache\]") {$env:APPVEYOR_CACHE_SKIP_RESTORE = "true"} - -# Install scripts. (runs after repo cloning) -install: - - ps: Install-Product node 8 x64 - - npm install -g npm@^5 - # Typical npm stuff. - # - set CI=true - # Our E2E work dir - - set TS_JEST_E2E_WORKDIR=%APPDATA%\ts-jest-e2e - - set TS_JEST_E2E_OPTIMIZATIONS=1 - - npm ci --ignore-scripts - - npm run clean -- --when-ci-commit-message - -cache: - - .cache -> package.json - - '%APPDATA%\npm-cache' - - '%APPDATA%\ts-jest-e2e\__templates__' - -# Post-install test scripts. -test_script: - - cmd: npm run test:e2e - -# skip_commits: -# files: -# - 'docs/**/*' -# - '**/*.md' -# - .gitignore -# - .gitattributes -# - .travis.yml -# - icon.png -# - commitlint.config.js diff --git a/e2e/__tests__/__snapshots__/logger.test.ts.snap b/e2e/__tests__/__snapshots__/logger.test.ts.snap index f1998d5850..e388cdb108 100644 --- a/e2e/__tests__/__snapshots__/logger.test.ts.snap +++ b/e2e/__tests__/__snapshots__/logger.test.ts.snap @@ -22,14 +22,14 @@ Array [ "[level:20] file caching disabled", "[level:20] initializeLanguageServiceInstance(): create typescript compiler", "[level:20] compileUsingLanguageService(): creating language service", - "[level:20] readThrough(): no cache", + "[level:20] compileAndCacheResult(): no cache", "[level:20] compileFn(): compiling using language service", "[level:20] updateMemoryCache(): update memory cache for language service", "[level:20] visitSourceFileNode(): hoisting", "[level:20] compileFn(): computing diagnostics for /Hello.spec.ts using language service", "[level:20] computing cache key for /Hello.ts", "[level:20] processing /Hello.ts", - "[level:20] readThrough(): no cache", + "[level:20] compileAndCacheResult(): no cache", "[level:20] compileFn(): compiling using language service", "[level:20] updateMemoryCache(): update memory cache for language service", "[level:20] visitSourceFileNode(): hoisting", @@ -63,7 +63,7 @@ Array [ "[level:20] file caching disabled", "[level:20] initializeLanguageServiceInstance(): create typescript compiler", "[level:20] compileUsingLanguageService(): creating language service", - "[level:20] readThrough(): no cache", + "[level:20] compileAndCacheResult(): no cache", "[level:20] compileFn(): compiling using language service", "[level:20] updateMemoryCache(): update memory cache for language service", "[level:20] visitSourceFileNode(): hoisting", @@ -71,7 +71,7 @@ Array [ "[level:20] calling babel-jest processor", "[level:20] computing cache key for /Hello.ts", "[level:20] processing /Hello.ts", - "[level:20] readThrough(): no cache", + "[level:20] compileAndCacheResult(): no cache", "[level:20] compileFn(): compiling using language service", "[level:20] updateMemoryCache(): update memory cache for language service", "[level:20] visitSourceFileNode(): hoisting", @@ -107,7 +107,7 @@ Array [ "[level:20] file caching disabled", "[level:20] initializeLanguageServiceInstance(): create typescript compiler", "[level:20] compileUsingLanguageService(): creating language service", - "[level:20] readThrough(): no cache", + "[level:20] compileAndCacheResult(): no cache", "[level:20] compileFn(): compiling using language service", "[level:20] updateMemoryCache(): update memory cache for language service", "[level:20] visitSourceFileNode(): hoisting", @@ -115,7 +115,7 @@ Array [ "[level:20] calling babel-jest processor", "[level:20] computing cache key for /Hello.ts", "[level:20] processing /Hello.ts", - "[level:20] readThrough(): no cache", + "[level:20] compileAndCacheResult(): no cache", "[level:20] compileFn(): compiling using language service", "[level:20] updateMemoryCache(): update memory cache for language service", "[level:20] visitSourceFileNode(): hoisting", diff --git a/package.json b/package.json index 12644b96a8..fd4816e483 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts-jest", - "version": "25.4.0", + "version": "25.5.0-alpha.0", "main": "dist/index.js", "types": "dist/index.d.ts", "bin": "cli.js", diff --git a/src/__helpers__/fakers.ts b/src/__helpers__/fakers.ts index 210e129c24..42aff8eec0 100644 --- a/src/__helpers__/fakers.ts +++ b/src/__helpers__/fakers.ts @@ -72,6 +72,8 @@ export function makeCompiler({ ...jestConfig, testMatch: ['^.+\\.tsx?$'], testRegex: jestConfig?.testRegex ? [...testRegex, ...jestConfig.testRegex] : testRegex, + setupFiles: [], + setupFilesAfterEnv: [], } const cs = new ConfigSet(getJestConfig(jestConfig, tsJestConfig), parentConfig) diff --git a/src/compiler/compiler-utils.spec.ts b/src/compiler/compiler-utils.spec.ts deleted file mode 100644 index e53f1687ee..0000000000 --- a/src/compiler/compiler-utils.spec.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { logger } from 'bs-logger' -import * as fs from 'fs' -import { resolve } from 'path' - -import { makeCompiler } from '../__helpers__/fakers' -import { tempDir } from '../__helpers__/path' -import { MemoryCache, TSFile } from '../types' - -import { cacheResolvedModules, getResolvedModulesCache } from './compiler-utils' - -const memoryCache: MemoryCache = { - contents: Object.create(null), - versions: Object.create(null), - outputs: Object.create(null), - resolvedModules: Object.create(null), - files: new Map(), -} - -describe('cacheResolvedModules', () => { - let spy: jest.SpyInstance - - beforeAll(() => { - // tslint:disable-next-line:no-empty - spy = jest.spyOn(fs, 'writeFileSync') - }) - - beforeEach(() => { - memoryCache.resolvedModules = Object.create(null) - }) - - afterEach(() => { - spy.mockRestore() - }) - - it('should store resolved modules in memory cache and file system when there are resolved modules', () => { - const tmp = tempDir('compiler') - const compiler = makeCompiler({ - jestConfig: { cache: true, cacheDirectory: tmp }, - tsJestConfig: { tsConfig: false }, - }) - const fileName = 'src/__mocks__/main.spec.ts' - const source = JSON.stringify(require('../__mocks__/main.spec')) - - compiler.compile(source, fileName) - cacheResolvedModules(fileName, source, memoryCache, compiler.program!, tmp, logger) - - expect(memoryCache.resolvedModules[fileName].modulePaths).toContain(resolve('src/__mocks__/main.ts')) - expect(memoryCache.resolvedModules[fileName].testFileContent).toEqual(source) - expect(spy).toHaveBeenCalledWith(getResolvedModulesCache(tmp), JSON.stringify(memoryCache.resolvedModules)) - }) - - it(`should store resolved modules in memory cache but not file system when there aren't resolved modules`, () => { - const tmp = tempDir('compiler') - const compiler = makeCompiler({ - jestConfig: { cache: true, cacheDirectory: tmp }, - tsJestConfig: { tsConfig: false }, - }) - const fileName = 'src/__mocks__/thing.spec.ts' - const source = JSON.stringify(require('../__mocks__/thing.spec')) - - compiler.compile(source, fileName) - cacheResolvedModules(fileName, source, memoryCache, compiler.program!, tmp, logger) - - expect(memoryCache.resolvedModules[fileName]).toBeUndefined() - expect(spy).not.toHaveBeenCalled() - }) -}) diff --git a/src/compiler/compiler-utils.ts b/src/compiler/compiler-utils.ts index 7685a9bee7..d459f7dfba 100644 --- a/src/compiler/compiler-utils.ts +++ b/src/compiler/compiler-utils.ts @@ -12,18 +12,15 @@ import { sha1 } from '../util/sha1' /** * @internal */ -export const hasOwn = Object.prototype.hasOwnProperty -/** - * @internal - */ -export function getResolvedModulesCache(cachedir: string): string { - return join(cachedir, sha1('ts-jest-resolved-modules', '\x00')) +export function getResolvedModulesCache(cacheDir: string): string { + return join(cacheDir, sha1('ts-jest-resolved-modules', '\x00')) } /** * @internal * Get resolved modules of a test file and put into memory cache */ +/* istanbul ignore next (we leave this for e2e) */ export function cacheResolvedModules( fileName: string, fileContent: string, diff --git a/src/compiler/instance.ts b/src/compiler/instance.ts index 4058380927..1ea45a1b5c 100644 --- a/src/compiler/instance.ts +++ b/src/compiler/instance.ts @@ -32,7 +32,7 @@ import { Logger } from 'bs-logger' import { readFileSync, writeFileSync } from 'fs' import mkdirp = require('mkdirp') -import { basename, extname, join, normalize } from 'path' +import { basename, extname, join } from 'path' import { ConfigSet } from '../config/config-set' import { CompileFn, CompilerInstance, MemoryCache, TSFile, TsCompiler } from '../types' @@ -92,60 +92,54 @@ const isValidCacheContent = (contents: string): boolean => { * cache mode */ const compileAndCacheResult = ( - cachedir: string | undefined, + cacheDir: string | undefined, memoryCache: MemoryCache, compileFn: CompileFn, getExtension: (fileName: string) => string, logger: Logger, ) => { - if (!cachedir) { - return (code: string, fileName: string, lineOffset?: number) => { - const normalizedFileName = normalize(fileName) - - logger.debug({ normalizedFileName }, 'readThrough(): no cache') - - const [value, sourceMap] = compileFn(code, normalizedFileName, lineOffset) + return (code: string, fileName: string, lineOffset?: number) => { + function getCompileOutput(): string { + const [value, sourceMap] = compileFn(code, fileName, lineOffset) const output = updateOutput(value, fileName, sourceMap, getExtension) - memoryCache.outputs[normalizedFileName] = output + memoryCache.files.set(fileName, { + ...memoryCache.files.get(fileName)!, + output, + }) return output } - } - - // Make sure the cache directory exists before continuing. - mkdirp.sync(cachedir) - try { - const resolvedModulesCache = readFileSync(getResolvedModulesCache(cachedir), 'utf-8') - /* istanbul ignore next (covered by e2e) */ - memoryCache.resolvedModules = JSON.parse(resolvedModulesCache) - } catch (e) {} + if (!cacheDir) { + logger.debug({ fileName }, 'compileAndCacheResult(): no cache') - return (code: string, fileName: string, lineOffset?: number) => { - const normalizedFileName = normalize(fileName) - const cachePath = join(cachedir, getCacheName(code, normalizedFileName)) - const extension = getExtension(normalizedFileName) - const outputPath = `${cachePath}${extension}` - try { - const output = readFileSync(outputPath, 'utf8') - if (isValidCacheContent(output)) { - logger.debug({ normalizedFileName }, 'readThrough(): cache hit') - memoryCache.outputs[normalizedFileName] = output + return getCompileOutput() + } else { + const cachePath = join(cacheDir, getCacheName(code, fileName)) + const extension = getExtension(fileName) + const outputPath = `${cachePath}${extension}` + try { + const output = readFileSync(outputPath, 'utf8') + if (isValidCacheContent(output)) { + logger.debug({ fileName }, 'compileAndCacheResult(): cache hit') + memoryCache.files.set(fileName, { + ...memoryCache.files.get(fileName)!, + output, + }) - return output - } - } catch (err) {} + return output + } + } catch (err) {} - logger.debug({ fileName }, 'readThrough(): cache miss') + logger.debug({ fileName }, 'compileAndCacheResult(): cache miss') - const [value, sourceMap] = compileFn(code, normalizedFileName, lineOffset) - const output = updateOutput(value, normalizedFileName, sourceMap, getExtension) + const output = getCompileOutput() - logger.debug({ normalizedFileName, outputPath }, 'readThrough(): writing caches') + logger.debug({ fileName, outputPath }, 'compileAndCacheResult(): writing caches') - memoryCache.outputs[normalizedFileName] = output - writeFileSync(outputPath, output) + writeFileSync(outputPath, output) - return output + return output + } } } @@ -156,16 +150,13 @@ const compileAndCacheResult = ( export const createCompilerInstance = (configs: ConfigSet): TsCompiler => { const logger = configs.logger.child({ namespace: 'ts-compiler' }) const { - typescript: { options: compilerOptions, fileNames }, + typescript: { options: compilerOptions }, tsJest, } = configs - const cachedir = configs.tsCacheDir + const cacheDir = configs.tsCacheDir const ts = configs.compilerModule // Require the TypeScript compiler and configuration. const extensions = ['.ts', '.tsx'] const memoryCache: MemoryCache = { - contents: Object.create(null), - versions: Object.create(null), - outputs: Object.create(null), resolvedModules: Object.create(null), files: new Map(), } @@ -174,14 +165,21 @@ export const createCompilerInstance = (configs: ConfigSet): TsCompiler => { extensions.push('.js') extensions.push('.jsx') } - // Initialize files from TypeScript into project. - for (const path of fileNames) { - const normalizedFilePath = normalize(path) - memoryCache.versions[normalizedFilePath] = 1 - memoryCache.files.set(normalizedFilePath, { + if (cacheDir) { + // Make sure the cache directory exists before continuing. + mkdirp.sync(cacheDir) + try { + const resolvedModulesCache = readFileSync(getResolvedModulesCache(cacheDir), 'utf-8') + /* istanbul ignore next (covered by e2e) */ + memoryCache.resolvedModules = JSON.parse(resolvedModulesCache) + } catch (e) {} + } + /* istanbul ignore next (we leave this for e2e) */ + configs.jest.setupFiles.concat(configs.jest.setupFilesAfterEnv).forEach(setupFile => { + memoryCache.files.set(setupFile, { version: 0, }) - } + }) /** * Get the extension for a transpiled file. */ @@ -196,7 +194,7 @@ export const createCompilerInstance = (configs: ConfigSet): TsCompiler => { } else { compilerInstance = initializeTranspilerInstance(configs, memoryCache, logger) } - const compile = compileAndCacheResult(cachedir, memoryCache, compilerInstance.compileFn, getExtension, logger) + const compile = compileAndCacheResult(cacheDir, memoryCache, compilerInstance.compileFn, getExtension, logger) return { cwd: configs.cwd, compile, program: compilerInstance.program } } diff --git a/src/compiler/language-service.spec.ts b/src/compiler/language-service.spec.ts index cb4e0abb39..90b0efa08a 100644 --- a/src/compiler/language-service.spec.ts +++ b/src/compiler/language-service.spec.ts @@ -1,11 +1,11 @@ import { LogLevels } from 'bs-logger' import { removeSync, writeFileSync } from 'fs-extra' -import { normalize } from 'path' import { makeCompiler } from '../__helpers__/fakers' import { logTargetMock } from '../__helpers__/mocks' import { tempDir } from '../__helpers__/path' import ProcessedSource from '../__helpers__/processed-source' +import { normalizeSlashes } from '../util/normalize-slashes' import * as compilerUtils from './compiler-utils' @@ -32,7 +32,7 @@ describe('Language service', () => { expect(logTarget.filteredLines(LogLevels.debug, Infinity)).toMatchInlineSnapshot(` Array [ - "[level:20] readThrough(): cache miss + "[level:20] compileAndCacheResult(): cache miss ", "[level:20] compileFn(): compiling using language service ", @@ -42,7 +42,7 @@ describe('Language service', () => { ", "[level:20] compileFn(): computing diagnostics for test-cache.ts using language service ", - "[level:20] readThrough(): writing caches + "[level:20] compileAndCacheResult(): writing caches ", ] `) @@ -52,7 +52,7 @@ describe('Language service', () => { expect(logTarget.lines).toMatchInlineSnapshot(` Array [ - "[level:20] readThrough(): cache hit + "[level:20] compileAndCacheResult(): cache hit ", ] `) @@ -123,12 +123,14 @@ describe('Language service', () => { tsJestConfig: { tsConfig: false }, }) const fileName = 'src/__mocks__/main.spec.ts' - const source = JSON.stringify(require('../__mocks__/main.spec')) + const source = `import { Thing } from './main' + +export const thing: Thing = { a: 1 }` compiler.compile(source, fileName) expect(spy).toHaveBeenCalled() - expect(spy.mock.calls[0][0]).toEqual(normalize(fileName)) + expect(spy.mock.calls[0][0]).toEqual(normalizeSlashes(fileName)) expect(spy.mock.calls[0][1]).toEqual(source) spy.mockRestore() @@ -143,7 +145,9 @@ describe('Language service', () => { tsJestConfig: { tsConfig: false }, }) const fileName = 'src/__mocks__/main.spec.ts' - const source = JSON.stringify(require('../__mocks__/main.spec')) + const source = `import { Thing } from './main' + +export const thing: Thing = { a: 1 }` compiler.compile(source, fileName) diff --git a/src/compiler/language-service.ts b/src/compiler/language-service.ts index 1f462e2aef..b0483e518f 100644 --- a/src/compiler/language-service.ts +++ b/src/compiler/language-service.ts @@ -12,7 +12,6 @@ import { cacheResolvedModules, getAndCacheProjectReference, getCompileResultFromReferencedProject, - hasOwn, isTestFile, } from './compiler-utils' @@ -38,7 +37,7 @@ export const initializeLanguageServiceInstance = ( const ts = configs.compilerModule const cwd = configs.cwd const cacheDir = configs.tsCacheDir - const { options, projectReferences } = configs.typescript + const { options, projectReferences, fileNames } = configs.typescript const serviceHostTraceCtx = { namespace: 'ts:serviceHost', call: null, @@ -46,29 +45,36 @@ export const initializeLanguageServiceInstance = ( } let projectVersion = 1 // Set the file contents into cache. + /* istanbul ignore next (cover by e2e) */ const updateMemoryCache = (contents: string, fileName: string) => { logger.debug({ fileName }, `updateMemoryCache(): update memory cache for language service`) - const file = memoryCache.files.get(fileName) - /* istanbul ignore next (covered by e2e) */ - if (file && file?.text !== contents) { - file.version++ - file.text = contents - } let shouldIncrementProjectVersion = false - const fileVersion = memoryCache.versions[fileName] ?? 0 - const isFileInCache = fileVersion !== 0 + const isFileInCache = memoryCache.files.has(fileName) && memoryCache.files.get(fileName)!.version !== 0 if (!isFileInCache) { - memoryCache.versions[fileName] = 1 + memoryCache.files.set(fileName, { + text: contents, + version: 1, + }) shouldIncrementProjectVersion = true - } - const previousContents = memoryCache.contents[fileName] - // Avoid incrementing cache when nothing has changed. - if (previousContents !== contents) { - memoryCache.versions[fileName] = fileVersion + 1 - memoryCache.contents[fileName] = contents - // Only bump project version when file is modified in cache, not when discovered for the first time - if (isFileInCache) shouldIncrementProjectVersion = true + } else { + const previousContents = memoryCache.files.get(fileName)!.text + // Avoid incrementing cache when nothing has changed. + if (previousContents !== contents) { + memoryCache.files.set(fileName, { + version: memoryCache.files.get(fileName)!.version + 1, + text: contents, + }) + // Only bump project version when file is modified in cache, not when discovered for the first time + if (isFileInCache) shouldIncrementProjectVersion = true + } + /** + * When a file is from node_modules or referenced to a referenced project and jest wants to transform it, we need + * to make sure that the Program is updated with this information + */ + if (!fileNames.includes(fileName)) { + shouldIncrementProjectVersion = true + } } if (shouldIncrementProjectVersion) projectVersion++ @@ -76,10 +82,10 @@ export const initializeLanguageServiceInstance = ( const serviceHost: _ts.LanguageServiceHost = { getProjectVersion: () => String(projectVersion), getProjectReferences: () => projectReferences, - getScriptFileNames: () => Object.keys(memoryCache.versions), + getScriptFileNames: () => [...memoryCache.files.keys()], getScriptVersion: (fileName: string) => { const normalizedFileName = normalize(fileName) - const version = memoryCache.versions[normalizedFileName] + const version = memoryCache.files.get(normalizedFileName)!.version // We need to return `undefined` and not a string here because TypeScript will use // `getScriptVersion` and compare against their own version - which can be `undefined`. @@ -90,13 +96,18 @@ export const initializeLanguageServiceInstance = ( }, getScriptSnapshot(fileName: string) { const normalizedFileName = normalize(fileName) - const hit = hasOwn.call(memoryCache.contents, normalizedFileName) + const hit = memoryCache.files.has(normalizedFileName) && memoryCache.files.get(normalizedFileName)!.version !== 0 logger.trace({ normalizedFileName, cacheHit: hit }, `getScriptSnapshot():`, 'cache', hit ? 'hit' : 'miss') // Read contents from TypeScript memory cache. - if (!hit) memoryCache.contents[normalizedFileName] = ts.sys.readFile(normalizedFileName) - const contents = memoryCache.contents[normalizedFileName] + if (!hit) { + memoryCache.files.set(normalizedFileName, { + version: 1, + text: ts.sys.readFile(normalizedFileName), + }) + } + const contents = memoryCache.files.get(normalizedFileName)!.text if (contents === undefined) return @@ -116,37 +127,37 @@ export const initializeLanguageServiceInstance = ( } logger.debug('compileUsingLanguageService(): creating language service') + const service: _ts.LanguageService = ts.createLanguageService(serviceHost, ts.createDocumentRegistry()) return { compileFn: (code: string, fileName: string): SourceOutput => { - const normalizedFileName = normalize(fileName) + logger.debug({ fileName }, 'compileFn(): compiling using language service') - logger.debug({ normalizedFileName }, 'compileFn(): compiling using language service') // Must set memory cache before attempting to read file. - updateMemoryCache(code, normalizedFileName) + updateMemoryCache(code, fileName) const referencedProject = getAndCacheProjectReference( - normalizedFileName, + fileName, service.getProgram()!, memoryCache.files, projectReferences, ) if (referencedProject !== undefined) { - logger.debug({ normalizedFileName }, 'compileFn(): get compile result from referenced project') + logger.debug({ fileName }, 'compileFn(): get compile result from referenced project') - return getCompileResultFromReferencedProject(normalizedFileName, configs, memoryCache.files, referencedProject) + return getCompileResultFromReferencedProject(fileName, configs, memoryCache.files, referencedProject) } else { - const output: _ts.EmitOutput = service.getEmitOutput(normalizedFileName) + const output: _ts.EmitOutput = service.getEmitOutput(fileName) // Do type checking by getting TypeScript diagnostics - logger.debug(`compileFn(): computing diagnostics for ${normalizedFileName} using language service`) + logger.debug(`compileFn(): computing diagnostics for ${fileName} using language service`) - doTypeChecking(configs, normalizedFileName, service, logger) + doTypeChecking(configs, fileName, service, logger) /** * We don't need the following logic with no cache run because no cache always gives correct typing */ if (cacheDir) { - if (isTestFile(configs.testMatchPatterns, normalizedFileName)) { - cacheResolvedModules(normalizedFileName, code, memoryCache, service.getProgram()!, cacheDir, logger) + if (isTestFile(configs.testMatchPatterns, fileName)) { + cacheResolvedModules(fileName, code, memoryCache, service.getProgram()!, cacheDir, logger) } else { /* istanbul ignore next (covered by e2e) */ Object.entries(memoryCache.resolvedModules) @@ -157,13 +168,12 @@ export const initializeLanguageServiceInstance = ( * test file for 1st time run after clearing cache because */ return ( - entry[1].modulePaths.find(modulePath => modulePath === normalizedFileName) && - !hasOwn.call(memoryCache.outputs, entry[0]) + entry[1].modulePaths.find(modulePath => modulePath === fileName) && !memoryCache.files.has(entry[0]) ) }) .forEach(entry => { logger.debug( - `compileFn(): computing diagnostics for test file that imports ${normalizedFileName} using language service`, + `compileFn(): computing diagnostics for test file that imports ${fileName} using language service`, ) const testFileName = entry[0] @@ -174,13 +184,13 @@ export const initializeLanguageServiceInstance = ( } /* istanbul ignore next (this should never happen but is kept for security) */ if (output.emitSkipped) { - throw new TypeError(`${relative(cwd, normalizedFileName)}: Emit skipped for language service`) + throw new TypeError(`${relative(cwd, fileName)}: Emit skipped for language service`) } // Throw an error when requiring `.d.ts` files. if (!output.outputFiles.length) { throw new TypeError( interpolate(Errors.UnableToRequireDefinitionFile, { - file: basename(normalizedFileName), + file: basename(fileName), }), ) } diff --git a/src/compiler/transpiler.spec.ts b/src/compiler/transpiler.spec.ts index e79bf0cb48..3e6066781a 100644 --- a/src/compiler/transpiler.spec.ts +++ b/src/compiler/transpiler.spec.ts @@ -31,7 +31,7 @@ describe('Transpiler', () => { expect(spy).toHaveBeenCalled() expect(logTarget.filteredLines(LogLevels.debug, Infinity)).toMatchInlineSnapshot(` Array [ - "[level:20] readThrough(): no cache + "[level:20] compileAndCacheResult(): no cache ", "[level:20] compileFn(): compiling as isolated module ", @@ -170,14 +170,18 @@ describe('Transpiler', () => { it('should have correct source maps', () => { const compiler = makeCompiler({ tsJestConfig: { ...baseTsJestConfig, tsConfig: false } }) const source = 'const f = (v: number) => v\nconst t: number = f(5)' + const fileName = 'test-source-map-transpiler.ts' + writeFileSync(fileName, source, 'utf8') - const compiled = compiler.compile(source, __filename) + const compiled = compiler.compile(source, fileName) - expect(new ProcessedSource(compiled, __filename).outputSourceMaps).toMatchObject({ - file: __filename, - sources: [__filename], + expect(new ProcessedSource(compiled, fileName).outputSourceMaps).toMatchObject({ + file: fileName, + sources: [fileName], sourcesContent: [source], }) + + removeSync(fileName) }) it('should not report diagnostics related to typings', () => { diff --git a/src/compiler/transpiler.ts b/src/compiler/transpiler.ts index a93fcfb23d..c25b844234 100644 --- a/src/compiler/transpiler.ts +++ b/src/compiler/transpiler.ts @@ -1,5 +1,4 @@ import { Logger } from 'bs-logger' -import { normalize } from 'path' import * as _ts from 'typescript' import { ConfigSet } from '../config/config-set' @@ -26,6 +25,7 @@ export const initializeTranspilerInstance = ( projectReferences, }) : ts.createProgram([], options) + /* istanbul ignore next (we leave this for e2e) */ const updateFileInCache = (contents: string, filePath: string) => { const file = memoryCache.files.get(filePath) if (file && file.text !== contents) { @@ -36,31 +36,24 @@ export const initializeTranspilerInstance = ( return { compileFn: (code: string, fileName: string): SourceOutput => { - const normalizedFileName = normalize(fileName) - - updateFileInCache(code, normalizedFileName) - const referencedProject = getAndCacheProjectReference( - normalizedFileName, - program, - memoryCache.files, - projectReferences, - ) + updateFileInCache(code, fileName) + const referencedProject = getAndCacheProjectReference(fileName, program, memoryCache.files, projectReferences) /* istanbul ignore next (referencedProject object is too complex to mock so we leave this for e2e) */ if (referencedProject !== undefined) { - logger.debug({ normalizedFileName }, 'compileFn(): get compile result from referenced project') + logger.debug({ fileName }, 'compileFn(): get compile result from referenced project') - return getCompileResultFromReferencedProject(normalizedFileName, configs, memoryCache.files, referencedProject) + return getCompileResultFromReferencedProject(fileName, configs, memoryCache.files, referencedProject) } else { - logger.debug({ normalizedFileName }, 'compileFn(): compiling as isolated module') + logger.debug({ fileName }, 'compileFn(): compiling as isolated module') const result: _ts.TranspileOutput = ts.transpileModule(code, { - fileName: normalizedFileName, + fileName, transformers: configs.tsCustomTransformers, compilerOptions: options, - reportDiagnostics: configs.shouldReportDiagnostic(normalizedFileName), + reportDiagnostics: configs.shouldReportDiagnostic(fileName), }) - if (result.diagnostics && configs.shouldReportDiagnostic(normalizedFileName)) { - configs.raiseDiagnostics(result.diagnostics, normalizedFileName, logger) + if (result.diagnostics && configs.shouldReportDiagnostic(fileName)) { + configs.raiseDiagnostics(result.diagnostics, fileName, logger) } return [result.outputText, result.sourceMapText!] diff --git a/src/config/config-set.spec.ts b/src/config/config-set.spec.ts index 6f4a250141..4f6cdf8664 100644 --- a/src/config/config-set.spec.ts +++ b/src/config/config-set.spec.ts @@ -52,6 +52,7 @@ function createConfigSet({ Object.keys(others).forEach(key => { Object.defineProperty(cs, key, { value: others[key] }) }) + return cs } @@ -875,7 +876,10 @@ describe('shouldReportDiagnostic', () => { describe('tsCompiler', () => { it('should be a compiler object', () => { - const cs = createConfigSet({ tsJestConfig: { tsConfig: false } as any }) + const cs = createConfigSet({ + tsJestConfig: { tsConfig: false } as any, + jestConfig: { setupFiles: [], setupFilesAfterEnv: [] } as any, + }) const compiler = cs.tsCompiler expect(compiler.cwd).toBe(cs.cwd) expect(typeof compiler.compile).toBe('function') diff --git a/src/types.ts b/src/types.ts index 6061dba0d6..8118577fdc 100644 --- a/src/types.ts +++ b/src/types.ts @@ -211,9 +211,6 @@ export type SourceOutput = [string, string] * @internal */ export interface MemoryCache { - contents: { [filePath: string]: string | undefined } - versions: { [filePath: string]: number } - outputs: { [filePath: string]: string } resolvedModules: { [testFilePath: string]: { testFileContent: string @@ -245,6 +242,7 @@ export interface AstTransformerDesc { export type TSFiles = Map export interface TSFile { text?: string + output?: string version: number projectReference?: { /**