Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: revert usage of @jest/create-cache-key-function #2108

Merged
merged 1 commit into from
Nov 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions e2e/__tests__/__snapshots__/coverage.test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`using template "default" should report coverages 1`] = `
exports[`Code coverage should pass using template "default" 1`] = `
√ jest
↳ exit code: 0
===[ STDOUT ]===================================================================
Expand All @@ -23,7 +23,7 @@ exports[`using template "default" should report coverages 1`] = `
================================================================================
`;

exports[`using template "with-babel-7" should report coverages 1`] = `
exports[`Code coverage should pass using template "with-babel-7" 1`] = `
√ jest
↳ exit code: 0
===[ STDOUT ]===================================================================
Expand All @@ -46,7 +46,7 @@ exports[`using template "with-babel-7" should report coverages 1`] = `
================================================================================
`;

exports[`using template "with-babel-7-string-config" should report coverages 1`] = `
exports[`Code coverage should pass using template "with-babel-7-string-config" 1`] = `
√ jest
↳ exit code: 0
===[ STDOUT ]===================================================================
Expand Down
14 changes: 7 additions & 7 deletions e2e/__tests__/coverage.test.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { allValidPackageSets } from '../__helpers__/templates'
import { configureTestCase } from '../__helpers__/test-case'

const testCase = configureTestCase('simple', {
jestConfig: { collectCoverage: true },
})
describe('Code coverage', () => {
const testCase = configureTestCase('simple', {
jestConfig: { collectCoverage: true },
})

testCase.runWithTemplates(allValidPackageSets, 0, (runTest, { templateName }) => {
describe(`using template "${templateName}"`, () => {
const result = runTest()
testCase.runWithTemplates(allValidPackageSets, 0, (runTest, { testLabel }) => {
it(testLabel, () => {
const result = runTest()

it(`should report coverages`, () => {
expect(result.status).toBe(0)
expect(result).toMatchSnapshot()
})
Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@
},
"homepage": "https://kulshekhar.github.io/ts-jest",
"dependencies": {
"@jest/create-cache-key-function": "^26.5.0",
"@types/jest": "26.x",
"bs-logger": "0.x",
"buffer-from": "1.x",
Expand Down
45 changes: 17 additions & 28 deletions src/ts-jest-transformer.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { LogLevels } from 'bs-logger'
import { sep } from 'path'

import { TsJestTransformer } from './ts-jest-transformer'
import { ConfigSet } from './config/config-set'
Expand All @@ -12,39 +13,24 @@ beforeEach(() => {
})

describe('TsJestTransformer', () => {
describe('createOrResolveTransformerCfg', () => {
it('should return the same config-set for same values with jest config string is not in cachedConfigSets', () => {
const obj1 = { cwd: '/foo/.' } as any
const tjT = new TsJestTransformer()

logTarget.clear()

tjT.getCacheKey('foo', 'foo', JSON.stringify(obj1), {
config: obj1,
} as any)
describe('configFor', () => {
it('should return the same config-set for same values with jest config string is not in configSetsIndex', () => {
const obj1 = { cwd: '/foo/.', rootDir: '/bar//dummy/..', globals: {} }
const cs3 = new TsJestTransformer().configsFor(obj1 as any)

expect(logTarget.lines[0]).toMatchInlineSnapshot(`
"[level:30] no matching config-set found, creating a new one
"
`)
expect(cs3.cwd).toBe(`${sep}foo`)
expect(cs3.rootDir).toBe(`${sep}bar`)
})

it('should return the same config-set for same values with jest config string in cachedConfigSets', () => {
it('should return the same config-set for same values with jest config string in configSetsIndex', () => {
const obj1 = { cwd: '/foo/.', rootDir: '/bar//dummy/..', globals: {} }
const obj2 = { ...obj1 }
const tjT1 = new TsJestTransformer()
const tjT2 = new TsJestTransformer()

logTarget.clear()
const cs1 = new TsJestTransformer().configsFor(obj1 as any)
const cs2 = new TsJestTransformer().configsFor(obj2 as any)

tjT1.getCacheKey('foo', 'foo', JSON.stringify(obj1), {
config: obj1,
} as any)
tjT2.getCacheKey('foo', 'foo', JSON.stringify(obj2), {
config: obj2,
} as any)

expect(logTarget.filteredLines(LogLevels.info)).toHaveLength(1)
expect(cs1.cwd).toBe(`${sep}foo`)
expect(cs1.rootDir).toBe(`${sep}bar`)
expect(cs2).toBe(cs1)
})
})

Expand All @@ -63,10 +49,13 @@ describe('TsJestTransformer', () => {
tr.getCacheKey(input.fileContent, input.fileName, '{}', { ...input.options, instrument: true }),
tr.getCacheKey(input.fileContent, input.fileName, '{}', { ...input.options, rootDir: '/bar' }),
]

// each key should have correct length
for (const key of keys) {
expect(key).toHaveLength(32)
expect(key).toHaveLength(40)
}
// unique array should have same length
expect(keys.filter((k, i, all) => all.indexOf(k) === i)).toHaveLength(keys.length)
})
})

Expand Down
132 changes: 75 additions & 57 deletions src/ts-jest-transformer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import createCacheKey from '@jest/create-cache-key-function'
import type { CacheKeyOptions, TransformedSource, Transformer, TransformOptions } from '@jest/transform'
import type { Config } from '@jest/types'
import type { Logger } from 'bs-logger'
Expand All @@ -9,6 +8,7 @@ import { stringify } from './utils/json'
import { JsonableValue } from './utils/jsonable-value'
import { rootLogger } from './utils/logger'
import { Errors, interpolate } from './utils/messages'
import { sha1 } from './utils/sha1'

interface CachedConfigSet {
configSet: ConfigSet
Expand All @@ -25,14 +25,65 @@ export class TsJestTransformer implements Transformer {
private static readonly _cachedConfigSets: CachedConfigSet[] = []
protected readonly logger: Logger
protected _transformCfgStr!: string
protected _configSet!: ConfigSet

constructor() {
this.logger = rootLogger.child({ namespace: 'ts-jest-transformer' })

this.logger.debug('created new transformer')
}

/**
* @public
*/
configsFor(jestConfig: Config.ProjectConfig): ConfigSet {
const ccs: CachedConfigSet | undefined = TsJestTransformer._cachedConfigSets.find(
(cs) => cs.jestConfig.value === jestConfig,
)
let configSet: ConfigSet
if (ccs) {
this._transformCfgStr = ccs.transformerCfgStr
configSet = ccs.configSet
} else {
// try to look-it up by stringified version
const serializedJestCfg = stringify(jestConfig)
const serializedCcs = TsJestTransformer._cachedConfigSets.find(
(cs) => cs.jestConfig.serialized === serializedJestCfg,
)
if (serializedCcs) {
// update the object so that we can find it later
// this happens because jest first calls getCacheKey with stringified version of
// the config, and then it calls the transformer with the proper object
serializedCcs.jestConfig.value = jestConfig
this._transformCfgStr = serializedCcs.transformerCfgStr
configSet = serializedCcs.configSet
} else {
// create the new record in the index
this.logger.info('no matching config-set found, creating a new one')

configSet = new ConfigSet(jestConfig)
this._transformCfgStr = new JsonableValue({
digest: configSet.tsJestDigest,
babel: configSet.babelConfig,
...jestConfig,
tsconfig: {
options: configSet.parsedTsConfig.options,
raw: configSet.parsedTsConfig.raw,
},
}).serialized
TsJestTransformer._cachedConfigSets.push({
jestConfig: new JsonableValue(jestConfig),
configSet,
transformerCfgStr: this._transformCfgStr,
})
}
}

return configSet
}

/**
* @public
*/
process(
input: string,
filePath: Config.Path,
Expand All @@ -43,9 +94,10 @@ export class TsJestTransformer implements Transformer {

let result: string | TransformedSource
const source: string = input
const { hooks } = this._configSet
const shouldStringifyContent = this._configSet.shouldStringifyContent(filePath)
const babelJest = shouldStringifyContent ? undefined : this._configSet.babelJestTransformer
const configs = this.configsFor(jestConfig)
const { hooks } = configs
const shouldStringifyContent = configs.shouldStringifyContent(filePath)
const babelJest = shouldStringifyContent ? undefined : configs.babelJestTransformer
const isDefinitionFile = filePath.endsWith(DECLARATION_TYPE_EXT)
const isJsFile = JS_JSX_REGEX.test(filePath)
const isTsFile = !isDefinitionFile && TS_TSX_REGEX.test(filePath)
Expand All @@ -55,15 +107,15 @@ export class TsJestTransformer implements Transformer {
} else if (isDefinitionFile) {
// do not try to compile declaration files
result = ''
} else if (!this._configSet.parsedTsConfig.options.allowJs && isJsFile) {
} else if (!configs.parsedTsConfig.options.allowJs && isJsFile) {
// we've got a '.js' but the compiler option `allowJs` is not set or set to false
this.logger.warn({ fileName: filePath }, interpolate(Errors.GotJsFileButAllowJsFalse, { path: filePath }))

result = source
} else if (isJsFile || isTsFile) {
// transpile TS code (source maps are included)
/* istanbul ignore if */
result = this._configSet.tsCompiler.compile(source, filePath)
result = configs.tsCompiler.compile(source, filePath)
} else {
// we should not get called for files with other extension than js[x], ts[x] and d.ts,
// TypeScript will bail if we try to compile, and if it was to call babel, users can
Expand Down Expand Up @@ -99,66 +151,32 @@ export class TsJestTransformer implements Transformer {
* Jest uses this to cache the compiled version of a file
*
* @see https://github.com/facebook/jest/blob/v23.5.0/packages/jest-runtime/src/script_transformer.js#L61-L90
*
* @public
*/
getCacheKey(
fileContent: string,
filePath: string,
_jestConfigStr: string,
transformOptions: CacheKeyOptions,
): string {
this.createOrResolveTransformerCfg(transformOptions.config)
const configs = this.configsFor(transformOptions.config)

this.logger.debug({ fileName: filePath, transformOptions }, 'computing cache key for', filePath)

return createCacheKey()(fileContent, filePath, this._transformCfgStr, {
config: transformOptions.config,
instrument: false,
})
}

/**
* Users can override this method and provide their own config class
*/
protected createOrResolveTransformerCfg(jestConfig: Config.ProjectConfig): void {
const ccs: CachedConfigSet | undefined = TsJestTransformer._cachedConfigSets.find(
(cs) => cs.jestConfig.value === jestConfig,
// we do not instrument, ensure it is false all the time
const { instrument = false, rootDir = configs.rootDir } = transformOptions

return sha1(
this._transformCfgStr,
'\x00',
rootDir,
'\x00',
`instrument:${instrument ? 'on' : 'off'}`,
'\x00',
fileContent,
'\x00',
filePath,
)
if (ccs) {
this._transformCfgStr = ccs.transformerCfgStr
this._configSet = ccs.configSet
} else {
// try to look-it up by stringified version
const serializedJestCfg = stringify(jestConfig)
const serializedCcs = TsJestTransformer._cachedConfigSets.find(
(cs) => cs.jestConfig.serialized === serializedJestCfg,
)
if (serializedCcs) {
// update the object so that we can find it later
// this happens because jest first calls getCacheKey with stringified version of
// the config, and then it calls the transformer with the proper object
serializedCcs.jestConfig.value = jestConfig
this._transformCfgStr = serializedCcs.transformerCfgStr
this._configSet = serializedCcs.configSet
} else {
// create the new record in the index
this.logger.info('no matching config-set found, creating a new one')

this._configSet = new ConfigSet(jestConfig)
this._transformCfgStr = new JsonableValue({
digest: this._configSet.tsJestDigest,
babel: this._configSet.babelConfig,
...jestConfig,
tsconfig: {
options: this._configSet.parsedTsConfig.options,
raw: this._configSet.parsedTsConfig.raw,
},
}).serialized
TsJestTransformer._cachedConfigSets.push({
jestConfig: new JsonableValue(jestConfig),
configSet: this._configSet,
transformerCfgStr: this._transformCfgStr,
})
}
}
}
}