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

feat(config): allow to override readTsConfig #2063

Merged
merged 2 commits into from
Oct 26, 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
4 changes: 2 additions & 2 deletions src/compiler/language-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ export const initializeLanguageServiceInstance = (configs: ConfigSet, logger: Lo
}
// Initialize memory cache for typescript compiler
configs.parsedTsConfig.fileNames
.filter((fileName) => !configs.isTestFile(fileName))
.forEach((fileName) => {
.filter((fileName: string) => !configs.isTestFile(fileName))
.forEach((fileName: string) => {
memoryCache.files.set(fileName, {
version: 0,
})
Expand Down
104 changes: 52 additions & 52 deletions src/config/__snapshots__/config-set.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,57 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`_resolveTsConfig resolve configFileName normally module in tsConfig is not the same as forced module and allowSyntheticDefaultImports is false in tsConfig should use correct paths when searching 1`] = `
Array [
Object {
"category": 3,
"code": 151001,
"file": undefined,
"length": undefined,
"messageText": "If you have issues related to imports, you should consider setting \`esModuleInterop\` to \`true\` in your TypeScript configuration file (usually \`tsconfig.json\`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.",
"start": undefined,
},
]
`;

exports[`_resolveTsConfig resolve configFileName normally module in tsConfig is not the same as forced module and allowSyntheticDefaultImports is false in tsConfig should use given tsconfig path 1`] = `
Array [
Object {
"category": 3,
"code": 151001,
"file": undefined,
"length": undefined,
"messageText": "If you have issues related to imports, you should consider setting \`esModuleInterop\` to \`true\` in your TypeScript configuration file (usually \`tsconfig.json\`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.",
"start": undefined,
},
]
`;

exports[`_resolveTsConfig resolve configFileName normally module in tsConfig is not the same as forced module and esModuleInterop is not in tsConfig should use correct paths when searching 1`] = `
Array [
Object {
"category": 3,
"code": 151001,
"file": undefined,
"length": undefined,
"messageText": "If you have issues related to imports, you should consider setting \`esModuleInterop\` to \`true\` in your TypeScript configuration file (usually \`tsconfig.json\`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.",
"start": undefined,
},
]
`;

exports[`_resolveTsConfig resolve configFileName normally module in tsConfig is not the same as forced module and esModuleInterop is not in tsConfig should use given tsconfig path 1`] = `
Array [
Object {
"category": 3,
"code": 151001,
"file": undefined,
"length": undefined,
"messageText": "If you have issues related to imports, you should consider setting \`esModuleInterop\` to \`true\` in your TypeScript configuration file (usually \`tsconfig.json\`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.",
"start": undefined,
},
]
`;

exports[`customTransformers should return an object containing all resolved transformers 1`] = `
Object {
"before": Array [
Expand Down Expand Up @@ -55,55 +107,3 @@ exports[`isTestFile should return a boolean value whether the file matches test
exports[`isTestFile should return a boolean value whether the file matches test pattern 3`] = `true`;

exports[`isTestFile should return a boolean value whether the file matches test pattern 4`] = `true`;

exports[`readTsConfig resolve configFileName normally module in tsConfig is not the same as forced module and allowSyntheticDefaultImports is false in tsConfig should use correct paths when searching 1`] = `
Array [
Object {
"category": 3,
"code": 151001,
"file": undefined,
"length": undefined,
"messageText": "If you have issues related to imports, you should consider setting \`esModuleInterop\` to \`true\` in your TypeScript configuration file (usually \`tsconfig.json\`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.",
"start": undefined,
},
]
`;

exports[`readTsConfig resolve configFileName normally module in tsConfig is not the same as forced module and allowSyntheticDefaultImports is false in tsConfig should use given tsconfig path 1`] = `
Array [
Object {
"category": 3,
"code": 151001,
"file": undefined,
"length": undefined,
"messageText": "If you have issues related to imports, you should consider setting \`esModuleInterop\` to \`true\` in your TypeScript configuration file (usually \`tsconfig.json\`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.",
"start": undefined,
},
]
`;

exports[`readTsConfig resolve configFileName normally module in tsConfig is not the same as forced module and esModuleInterop is not in tsConfig should use correct paths when searching 1`] = `
Array [
Object {
"category": 3,
"code": 151001,
"file": undefined,
"length": undefined,
"messageText": "If you have issues related to imports, you should consider setting \`esModuleInterop\` to \`true\` in your TypeScript configuration file (usually \`tsconfig.json\`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.",
"start": undefined,
},
]
`;

exports[`readTsConfig resolve configFileName normally module in tsConfig is not the same as forced module and esModuleInterop is not in tsConfig should use given tsconfig path 1`] = `
Array [
Object {
"category": 3,
"code": 151001,
"file": undefined,
"length": undefined,
"messageText": "If you have issues related to imports, you should consider setting \`esModuleInterop\` to \`true\` in your TypeScript configuration file (usually \`tsconfig.json\`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.",
"start": undefined,
},
]
`;
2 changes: 1 addition & 1 deletion src/config/config-set.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,7 @@ describe('resolvePath', () => {
})
}) // resolvePath

describe('readTsConfig', () => {
describe('_resolveTsConfig', () => {
let findConfig!: jest.SpyInstance<string | undefined>
let readConfig!: jest.SpyInstance<{ config?: any; error?: ts.Diagnostic }>
let parseConfig!: jest.SpyInstance<ts.ParsedCommandLine>
Expand Down
22 changes: 11 additions & 11 deletions src/config/config-set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export class ConfigSet {
readonly isolatedModules: boolean
readonly cwd: string
tsCacheDir: string | undefined
parsedTsConfig!: ParsedCommandLine
parsedTsConfig!: ParsedCommandLine | Record<string, any>
customTransformers: CustomTransformers = Object.create(null)
readonly rootDir: string
/**
Expand All @@ -139,10 +139,7 @@ export class ConfigSet {
* @internal
*/
private _stringifyContentRegExp: RegExp | undefined
/**
* @internal
*/
private _overriddenCompilerOptions: Partial<CompilerOptions> = {
protected _overriddenCompilerOptions: Partial<CompilerOptions> = {
// we handle sourcemaps this way and not another
sourceMap: true,
inlineSourceMap: false,
Expand Down Expand Up @@ -282,7 +279,10 @@ export class ConfigSet {
}
const tsconfigOpt = options.tsConfig ?? options.tsconfig
const configFilePath = typeof tsconfigOpt === 'string' ? this.resolvePath(tsconfigOpt) : undefined
this.parsedTsConfig = this._readTsConfig(typeof tsconfigOpt === 'object' ? tsconfigOpt : undefined, configFilePath)
this.parsedTsConfig = this._resolveTsConfig(
typeof tsconfigOpt === 'object' ? tsconfigOpt : undefined,
configFilePath,
)
// throw errors if any matching wanted diagnostics
this.raiseDiagnostics(this.parsedTsConfig.errors, configFilePath)

Expand Down Expand Up @@ -389,10 +389,10 @@ export class ConfigSet {
/**
* Load TypeScript configuration. Returns the parsed TypeScript config and
* any `tsConfig` options specified in ts-jest tsConfig
*
* @internal
*/
private _readTsConfig(compilerOptions?: CompilerOptions, resolvedConfigFile?: string): ParsedCommandLine {
protected _resolveTsConfig(compilerOptions?: CompilerOptions, resolvedConfigFile?: string): Record<string, any>
// eslint-disable-next-line no-dupe-class-members
protected _resolveTsConfig(compilerOptions?: CompilerOptions, resolvedConfigFile?: string): ParsedCommandLine {
let config = { compilerOptions: Object.create(null) }
let basePath = normalizeSlashes(this.rootDir)
const ts = this.compilerModule
Expand All @@ -402,6 +402,7 @@ export class ConfigSet {
: ts.findConfigFile(normalizeSlashes(this.rootDir), ts.sys.fileExists)
if (configFileName) {
this.logger.debug({ tsConfigFileName: configFileName }, 'readTsConfig(): reading', configFileName)

const result = ts.readConfigFile(configFileName, ts.sys.readFile)
// Return diagnostics.
if (result.error) {
Expand All @@ -419,10 +420,8 @@ export class ConfigSet {

// parse json, merge config extending others, ...
const result = ts.parseJsonConfigFileContent(config, ts.sys, basePath, undefined, configFileName)

const { _overriddenCompilerOptions: forcedOptions } = this
const finalOptions = result.options

// Target ES5 output by default (instead of ES3).
if (finalOptions.target === undefined) {
finalOptions.target = ts.ScriptTarget.ES5
Expand Down Expand Up @@ -484,6 +483,7 @@ export class ConfigSet {
nodeJsVer: process.version,
compilationTarget: config.compilerOptions.target ?? TARGET_TO_VERSION_MAPPING[compilationTarget],
})

this.logger.warn(message)
}

Expand Down
4 changes: 1 addition & 3 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
/**
* @internal
*/
export const LINE_FEED = '\n'
export const TS_TSX_REGEX = /\.tsx?$/
export const JS_JSX_REGEX = /\.jsx?$/
export const DECLARATION_TYPE_EXT = '.d.ts'
/**
* @internal
* See https://jestjs.io/docs/en/configuration#testmatch-arraystring
Expand Down
40 changes: 17 additions & 23 deletions src/ts-jest-transformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { Config } from '@jest/types'
import type { Logger } from 'bs-logger'

import { ConfigSet } from './config/config-set'
import { JS_JSX_REGEX, TS_TSX_REGEX } from './constants'
import { DECLARATION_TYPE_EXT, JS_JSX_REGEX, TS_TSX_REGEX } from './constants'
import { stringify } from './utils/json'
import { JsonableValue } from './utils/jsonable-value'
import { rootLogger } from './utils/logger'
Expand All @@ -24,14 +24,8 @@ export class TsJestTransformer implements Transformer {
*/
private static readonly _cachedConfigSets: CachedConfigSet[] = []
protected readonly logger: Logger
/**
* @internal
*/
private _transformCfgStr!: string
/**
* @internal
*/
private _tsJestCfgSet!: ConfigSet
protected _transformCfgStr!: string
protected _configSet!: ConfigSet

constructor() {
this.logger = rootLogger.child({ namespace: 'ts-jest-transformer' })
Expand All @@ -49,10 +43,10 @@ export class TsJestTransformer implements Transformer {

let result: string | TransformedSource
const source: string = input
const { hooks } = this._tsJestCfgSet
const shouldStringifyContent = this._tsJestCfgSet.shouldStringifyContent(filePath)
const babelJest = shouldStringifyContent ? undefined : this._tsJestCfgSet.babelJestTransformer
const isDefinitionFile = filePath.endsWith('.d.ts')
const { hooks } = this._configSet
const shouldStringifyContent = this._configSet.shouldStringifyContent(filePath)
const babelJest = shouldStringifyContent ? undefined : this._configSet.babelJestTransformer
const isDefinitionFile = filePath.endsWith(DECLARATION_TYPE_EXT)
const isJsFile = JS_JSX_REGEX.test(filePath)
const isTsFile = !isDefinitionFile && TS_TSX_REGEX.test(filePath)
if (shouldStringifyContent) {
Expand All @@ -61,15 +55,15 @@ export class TsJestTransformer implements Transformer {
} else if (isDefinitionFile) {
// do not try to compile declaration files
result = ''
} else if (!this._tsJestCfgSet.parsedTsConfig.options.allowJs && isJsFile) {
} else if (!this._configSet.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._tsJestCfgSet.tsCompiler.compile(source, filePath)
result = this._configSet.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 @@ -131,7 +125,7 @@ export class TsJestTransformer implements Transformer {
)
if (ccs) {
this._transformCfgStr = ccs.transformerCfgStr
this._tsJestCfgSet = ccs.configSet
this._configSet = ccs.configSet
} else {
// try to look-it up by stringified version
const serializedJestCfg = stringify(jestConfig)
Expand All @@ -144,24 +138,24 @@ export class TsJestTransformer implements Transformer {
// the config, and then it calls the transformer with the proper object
serializedCcs.jestConfig.value = jestConfig
this._transformCfgStr = serializedCcs.transformerCfgStr
this._tsJestCfgSet = serializedCcs.configSet
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._tsJestCfgSet = new ConfigSet(jestConfig)
this._configSet = new ConfigSet(jestConfig)
this._transformCfgStr = new JsonableValue({
digest: this._tsJestCfgSet.tsJestDigest,
babel: this._tsJestCfgSet.babelConfig,
digest: this._configSet.tsJestDigest,
babel: this._configSet.babelConfig,
...jestConfig,
tsconfig: {
options: this._tsJestCfgSet.parsedTsConfig.options,
raw: this._tsJestCfgSet.parsedTsConfig.raw,
options: this._configSet.parsedTsConfig.options,
raw: this._configSet.parsedTsConfig.raw,
},
}).serialized
TsJestTransformer._cachedConfigSets.push({
jestConfig: new JsonableValue(jestConfig),
configSet: this._tsJestCfgSet,
configSet: this._configSet,
transformerCfgStr: this._transformCfgStr,
})
}
Expand Down