Skip to content

Commit e9f602f

Browse files
authored
Merge pull request #724 from huafu/allow-js-detection
[beta] warns the user if jest config transform matches js files without allowJs in tsconfig
2 parents 64ebc6d + 6c32a93 commit e9f602f

5 files changed

Lines changed: 81 additions & 14 deletions

File tree

src/ts-jest-transformer.spec.ts

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import stringify from 'fast-json-stable-stringify'
2+
import { ParsedCommandLine } from 'typescript'
23

4+
import { logTargetMock } from './__helpers__/mocks'
35
import { TsJestTransformer } from './ts-jest-transformer'
46

57
describe('configFor', () => {
@@ -31,8 +33,12 @@ describe('lastTransformerId', () => {
3133
describe('process', () => {
3234
let tr: TsJestTransformer
3335
let babel: any
36+
let typescript: ParsedCommandLine
3437
let args: [string, string, any, any]
3538
const config = {
39+
get typescript() {
40+
return typescript
41+
},
3642
shouldStringifyContent: jest.fn(),
3743
get babelJestTransformer() {
3844
return babel
@@ -53,12 +59,12 @@ describe('process', () => {
5359
.mockImplementation(() => config)
5460
.mockClear()
5561
config.shouldStringifyContent.mockImplementation(() => false).mockClear()
56-
babel = { process: jest.fn(s => `babel:${s}`) }
62+
babel = null
5763
config.tsCompiler.compile.mockImplementation(s => `ts:${s}`).mockClear()
64+
typescript = { options: {} } as any
5865
})
5966

6067
it('should process input without babel', () => {
61-
babel = null
6268
expect(process()).toBe(`ts:${INPUT}`)
6369
expect(config.shouldStringifyContent.mock.calls).toMatchInlineSnapshot(`
6470
Array [
@@ -78,6 +84,7 @@ Array [
7884
})
7985

8086
it('should process input with babel', () => {
87+
babel = { process: jest.fn(s => `babel:${s}`) }
8188
expect(process()).toBe(`babel:ts:${INPUT}`)
8289
expect(config.shouldStringifyContent.mock.calls).toMatchInlineSnapshot(`
8390
Array [
@@ -110,10 +117,49 @@ Array [
110117

111118
it('should return stringified version of file', () => {
112119
config.shouldStringifyContent.mockImplementation(() => true)
113-
expect(process()).toMatchInlineSnapshot(`"ts:module.exports=\\"export default \\\\\\"foo\\\\\\"\\""`)
120+
expect(process()).toMatchInlineSnapshot(`"module.exports=\\"export default \\\\\\"foo\\\\\\"\\""`)
121+
})
122+
123+
it('should warn when trying to process js but allowJs is false', () => {
124+
args[1] = '/foo/bar.js'
125+
typescript.options.allowJs = false
126+
const logs = logTargetMock()
127+
logs.clear()
128+
expect(process()).toBe(INPUT)
129+
expect(logs.lines.warn).toMatchInlineSnapshot(`
130+
Array [
131+
"[level:40] Got a \`.js\` file to compile while \`allowJs\` option is not set to \`true\` (file: /foo/bar.js). To fix this:
132+
- if you want TypeScript to process JS files, set \`allowJs\` to \`true\` in your TypeScript config (usually tsconfig.json)
133+
- if you do not want TypeScript to process your \`.js\` files, in your Jest config change the \`transform\` key which value is \`ts-jest\` so that it does not match \`.js\` files anymore
134+
",
135+
]
136+
`)
137+
})
138+
139+
it('should warn when trying to process unknown file types', () => {
140+
args[1] = '/foo/bar.jest'
141+
const logs = logTargetMock()
142+
logs.clear()
143+
expect(process()).toBe(INPUT)
144+
expect(logs.lines.warn).toMatchInlineSnapshot(`
145+
Array [
146+
"[level:40] Got a unknown file type to compile (file: /foo/bar.jest). To fix this, in your Jest config change the \`transform\` key which value is \`ts-jest\` so that it does not match this kind of files anymore.
147+
",
148+
]
149+
`)
150+
logs.clear()
151+
babel = { process: jest.fn(s => `babel:${s}`) }
152+
expect(process()).toBe(`babel:${INPUT}`)
153+
expect(logs.lines.warn).toMatchInlineSnapshot(`
154+
Array [
155+
"[level:40] Got a unknown file type to compile (file: /foo/bar.jest). To fix this, in your Jest config change the \`transform\` key which value is \`ts-jest\` so that it does not match this kind of files anymore. If you still want Babel to process it, add another entry to the \`transform\` option with value \`babel-jest\` which key matches this type of files.
156+
",
157+
]
158+
`)
114159
})
115160

116161
it('should not pass the instrument option to babel-jest', () => {
162+
babel = { process: jest.fn(s => `babel:${s}`) }
117163
args[3] = { instrument: true }
118164
expect(process()).toBe(`babel:ts:${INPUT}`)
119165
expect(config.babelJestTransformer.process.mock.calls).toMatchInlineSnapshot(`

src/ts-jest-transformer.ts

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { TsJestGlobalOptions } from './types'
66
import { parse, stringify } from './util/json'
77
import { JsonableValue } from './util/jsonable-value'
88
import { rootLogger } from './util/logger'
9+
import { Errors, interpolate } from './util/messages'
910
import { sha1 } from './util/sha1'
1011

1112
/**
@@ -88,24 +89,40 @@ export class TsJestTransformer implements jest.Transformer {
8889
): jest.TransformedSource | string {
8990
this.logger.debug({ fileName: filePath, transformOptions }, 'processing', filePath)
9091
let result: string | jest.TransformedSource
91-
let source: string = input
92+
const source: string = input
9293

9394
const configs = this.configsFor(jestConfig)
9495
const { hooks } = configs
9596

9697
const stringify = configs.shouldStringifyContent(filePath)
9798
const babelJest = stringify ? undefined : configs.babelJestTransformer
9899

99-
// handles here what we should simply stringify
100+
const isDefinitionFile = filePath.endsWith('.d.ts')
101+
const isJsFile = !isDefinitionFile && /\.jsx?$/.test(filePath)
102+
const isTsFile = isDefinitionFile || /\.tsx?$/.test(filePath)
103+
100104
if (stringify) {
101-
source = `module.exports=${JSON.stringify(source)}`
105+
// handles here what we should simply stringify
106+
result = `module.exports=${JSON.stringify(source)}`
107+
} else if (isDefinitionFile) {
108+
// do not try to compile declaration files
109+
result = ''
110+
} else if (!configs.typescript.options.allowJs && isJsFile) {
111+
// we've got a '.js' but the compiler option `allowJs` is not set or set to false
112+
this.logger.warn({ fileName: filePath }, interpolate(Errors.GotJsFileButAllowJsFalse, { path: filePath }))
113+
result = source
114+
} else if (isTsFile) {
115+
// transpile TS code (source maps are included)
116+
result = configs.tsCompiler.compile(source, filePath)
117+
} else {
118+
// we should not get called for files with other extension than js[x], ts[x] and d.ts,
119+
// TypeScript will bail if we try to compile, and if it was to call babel, users can
120+
// define the transform value with `babel-jest` for this extension instead
121+
const message = babelJest ? Errors.GotUnknownFileTypeWithBabel : Errors.GotUnknownFileTypeWithoutBabel
122+
this.logger.warn({ fileName: filePath }, interpolate(message, { path: filePath }))
123+
result = source
102124
}
103125

104-
// transpile TS code (source maps are included)
105-
result = filePath.endsWith('.d.ts')
106-
? '' // do not try to compile declaration files
107-
: configs.tsCompiler.compile(source, filePath)
108-
109126
// calling babel-jest transformer
110127
if (babelJest) {
111128
this.logger.debug({ fileName: filePath }, 'calling babel-jest processor')

src/util/messages.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ export enum Errors {
1212
NotMappingPathWithEmptyMap = 'Not mapping "{{path}}" because it has no target.',
1313
MappingOnlyFirstTargetOfPath = 'Mapping only to first target of "{{path}}" because it has more than one ({{count}}).',
1414
CannotPatchBabelCore6 = 'Error while trying to patch babel-core/lib/transformation/file: {{error}}',
15+
GotJsFileButAllowJsFalse = 'Got a `.js` file to compile while `allowJs` option is not set to `true` (file: {{path}}). To fix this:\n - if you want TypeScript to process JS files, set `allowJs` to `true` in your TypeScript config (usually tsconfig.json)\n - if you do not want TypeScript to process your `.js` files, in your Jest config change the `transform` key which value is `ts-jest` so that it does not match `.js` files anymore',
16+
GotUnknownFileTypeWithoutBabel = 'Got a unknown file type to compile (file: {{path}}). To fix this, in your Jest config change the `transform` key which value is `ts-jest` so that it does not match this kind of files anymore.',
17+
GotUnknownFileTypeWithBabel = 'Got a unknown file type to compile (file: {{path}}). To fix this, in your Jest config change the `transform` key which value is `ts-jest` so that it does not match this kind of files anymore. If you still want Babel to process it, add another entry to the `transform` option with value `babel-jest` which key matches this type of files.',
1518
}
1619

1720
export enum Helps {

tsconfig.build.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"sourceMap": false,
55
"inlineSources": false,
66
"inlineSourceMap": false,
7-
"removeComments": true,
7+
"noEmit": false,
88
"outDir": "dist",
99
"rootDir": "src",
1010
},

tsconfig.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"compilerOptions": {
3-
"declaration": true,
3+
"declaration": false,
4+
"noEmit": true,
45
"downlevelIteration": true,
56
"esModuleInterop": true,
67
"experimentalDecorators": true,
@@ -18,7 +19,7 @@
1819
"noImplicitReturns": true,
1920
"noUnusedLocals": true,
2021
"noUnusedParameters": true,
21-
"removeComments": false,
22+
"removeComments": true,
2223
"resolveJsonModule": true,
2324
"skipLibCheck": true,
2425
"sourceMap": false,

0 commit comments

Comments
 (0)