Skip to content

Commit

Permalink
fix(cli): change options to better reflect the new presets
Browse files Browse the repository at this point in the history
  • Loading branch information
huafu committed Oct 6, 2018
1 parent 33ff29f commit 68abcfb
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 48 deletions.
7 changes: 4 additions & 3 deletions docs/user/config/stringifyContentPathRegex.md
Expand Up @@ -18,16 +18,17 @@ In the `jest.config.js` version, you could do as in the `package.json` version o

```js
// jest.config.js
const { jestPreset } = require('ts-jest');
// Here `defaults` can be replaced with any other preset
const { defaults: tsjPreset } = require('ts-jest/presets');

module.exports = {
// [...]
moduleFileExtensions: [
...jestPreset.moduleFileExtensions,
...tsjPreset.moduleFileExtensions,
'html'
],
transform: {
...jestPreset.transform,
...tsjPreset.transform,
'\\.html$': 'ts-jest'
}
globals: {
Expand Down
2 changes: 1 addition & 1 deletion docs/user/install.md
Expand Up @@ -55,7 +55,7 @@ yarn ts-jest config:init
This will create a basic Jest configuration file which will make Jest know about your `.ts` files and handle them correctly.

You can also use the `jest --init` command (prefixed with either `npx` or `yarn` depending on what you're using) to have more options related to Jest.
However, answer `no` to the Jest question about whether or not to enable Typescript. Instead, add the line: `preset: "ts-jest"` to the the `jest.config.js` file afterwards.
However, answer `no` to the Jest question about whether or not to enable Typescript. Instead, add the line: `preset: "ts-jest"` to the `jest.config.js` file afterwards.

### Customizing

Expand Down
6 changes: 3 additions & 3 deletions docs/user/react-native/index.md
Expand Up @@ -25,13 +25,13 @@ In the same way that you moved Babel config, move Jest config from `jest` key of

```js
// jest.config.js
const { jestPreset: tsJest } = require('ts-jest');
const { defaults: tsjPreset } = require('ts-jest/presets');

module.exports = {
...tsJest,
...tsjPreset,
preset: 'react-native',
transform: {
...tsJest.transform,
...tsjPreset.transform,
'\\.js$': '<rootDir>/node_modules/react-native/jest/preprocessor.js',
},
globals: {
Expand Down
39 changes: 28 additions & 11 deletions src/cli/config/init.ts
Expand Up @@ -10,7 +10,7 @@ import { basename, join } from 'path'
import { Arguments } from 'yargs'

import { CliCommand } from '..'
import { createJestPreset } from '../../config/create-jest-preset'
import { TsJestPresetDescriptor, defaults, jsWIthBabel, jsWithTs } from '../helpers/presets'

/**
* @internal
Expand All @@ -24,12 +24,28 @@ export const run: CliCommand = async (args: Arguments /* , logger: Logger */) =>
const pkgFile = isPackage ? filePath : join(process.cwd(), 'package.json')
const hasPackage = isPackage || existsSync(pkgFile)
// read config
const { allowJs = false, jestPreset = true, tsconfig: askedTsconfig, babel = false, force, jsdom } = args
const { jestPreset = true, tsconfig: askedTsconfig, force, jsdom } = args
const tsconfig = askedTsconfig === 'tsconfig.json' ? undefined : askedTsconfig
const hasPresetVar = allowJs || !jestPreset
// read package
const pkgJson = hasPackage ? JSON.parse(readFileSync(pkgFile, 'utf8')) : {}

// auto js/babel
let { js, babel } = args
if (js != null || babel != null) {
if (js == null) js = babel ? 'babel' : undefined
else if (babel == null) babel = js === 'babel'
}

// preset
let preset: TsJestPresetDescriptor | undefined
if (js === 'babel') {
preset = jsWIthBabel
} else if (js === 'ts') {
preset = jsWithTs
} else {
preset = defaults
}

if (isPackage && !exists) {
throw new Error(`File ${file} does not exists.`)
} else if (!isPackage && exists && !force) {
Expand All @@ -52,7 +68,7 @@ export const run: CliCommand = async (args: Arguments /* , logger: Logger */) =>

if (isPackage) {
// package.json config
const base: any = hasPresetVar ? createJestPreset({ allowJs }) : { preset: 'ts-jest' }
const base: any = jestPreset ? { preset: preset.name } : { ...preset.value }
if (!jsdom) base.testEnvironment = 'node'
if (tsconfig || babel) {
const tsJestConf: any = {}
Expand All @@ -64,14 +80,14 @@ export const run: CliCommand = async (args: Arguments /* , logger: Logger */) =>
} else {
// js config
const content = []
if (hasPresetVar) {
content.push(`const tsJest = require('ts-jest').createJestPreset({ allowJs: ${allowJs} });`, '')
if (!jestPreset) {
content.push(`${preset.jsImport('tsjPreset')};`, '')
}
content.push('module.exports = {')
if (hasPresetVar) {
content.push(` ...tsJest,`)
if (jestPreset) {
content.push(` preset: '${preset.name}',`)
} else {
content.push(` preset: 'ts-jest',`)
content.push(` ...tsjPreset,`)
}
if (!jsdom) content.push(` testEnvironment: 'node',`)

Expand Down Expand Up @@ -113,10 +129,11 @@ Arguments:
Options:
--force Discard any existing Jest config
--allow-js ts-jest will be used to process JS files as well
--js ts|babel Process .js files with ts-jest if 'ts' or with
babel-jest if 'babel'
--no-jest-preset Disable the use of Jest presets
--tsconfig <file> Path to the tsconfig.json file
--babel Call BabelJest after ts-jest
--babel Pipe babel-jest after ts-jest
--jsdom Use jsdom as test environment instead of node
`)
}
60 changes: 30 additions & 30 deletions src/cli/config/migrate.ts
Expand Up @@ -6,10 +6,8 @@ import { basename, resolve } from 'path'
import { Arguments } from 'yargs'

import { CliCommand } from '..'
import { TsJestPresets } from '../../config/create-jest-preset'
import { backportJestConfig } from '../../util/backports'

const DEFAULT_PRESET = 'ts-jest/presets/default'
import { JestPresetNames, TsJestPresetDescriptor, allPresets, defaults } from '../helpers/presets'

/**
* @internal
Expand All @@ -36,12 +34,14 @@ export const run: CliCommand = async (args: Arguments /*, logger: Logger*/) => {
// migrate
// first we backport our options
const migratedConfig = backportJestConfig(nullLogger, actualConfig)
let presetName: string | undefined
let presetName: JestPresetNames | undefined
let preset: TsJestPresetDescriptor | undefined
// then we check if we can use `preset`
if (!migratedConfig.preset && args.jestPreset) {
// find the best preset
if (args.allowJs) presetName = 'ts-jest/presets/js-with-ts'
else {
if (args.js) {
presetName = args.js === 'babel' ? JestPresetNames.jsWIthBabel : JestPresetNames.jsWithTs
} else {
// try to detect what transformer the js extensions would target
const jsTransformers = Object.keys(migratedConfig.transform || {}).reduce(
(list, pattern) => {
Expand All @@ -59,49 +59,48 @@ export const run: CliCommand = async (args: Arguments /*, logger: Logger*/) => {
const jsWithTs = jsTransformers.includes('ts-jest')
const jsWithBabel = jsTransformers.includes('babel-jest')
if (jsWithBabel && !jsWithTs) {
presetName = 'ts-jest/presets/js-with-babel'
presetName = JestPresetNames.jsWIthBabel
} else if (jsWithTs && !jsWithBabel) {
presetName = 'ts-jest/presets/js-with-ts'
presetName = JestPresetNames.jsWithTs
} else {
// sounds like js files are NOT handled, or handled with a unknown transformer, so we do not need to handle it
presetName = DEFAULT_PRESET
presetName = JestPresetNames.default
}
}
// ensure we are using a preset
presetName = presetName || DEFAULT_PRESET
migratedConfig.preset = presetName
presetName = presetName || JestPresetNames.default
preset = allPresets[presetName]
footNotes.push(
`Detected preset '${presetName.replace(
/^ts-jest\/presets\//,
'',
)}' as the best matching preset for your configuration.\nVisit https://kulshekhar.github.io/ts-jest/user/config/#jest-preset for more information about presets.\n`,
`Detected preset '${preset.label}' as the best matching preset for your configuration.
Visit https://kulshekhar.github.io/ts-jest/user/config/#jest-preset for more information about presets.
`,
)
} else if (migratedConfig.preset && migratedConfig.preset.startsWith('ts-jest')) {
if (args.jestPreset === false) {
delete migratedConfig.preset
} else {
presetName = migratedConfig.preset
preset = (allPresets as any)[migratedConfig.preset] || defaults
}
}
const presets: TsJestPresets | undefined = presetName
? require(`../../../${presetName.replace(/^ts-jest\//, '')}/jest-preset`)
: undefined

// enforce the correct name
if (preset) migratedConfig.preset = preset.name

// check the extensions
if (migratedConfig.moduleFileExtensions && migratedConfig.moduleFileExtensions.length && presets) {
const presetValue = dedupSort(presets.moduleFileExtensions).join('::')
if (migratedConfig.moduleFileExtensions && migratedConfig.moduleFileExtensions.length && preset) {
const presetValue = dedupSort(preset.value.moduleFileExtensions).join('::')
const migratedValue = dedupSort(migratedConfig.moduleFileExtensions).join('::')
if (presetValue === migratedValue) {
delete migratedConfig.moduleFileExtensions
}
}
// there is a testRegex, remove our testMatch
if (migratedConfig.testRegex && presets) {
if (migratedConfig.testRegex && preset) {
migratedConfig.testMatch = null as any
}
// check the testMatch
else if (migratedConfig.testMatch && migratedConfig.testMatch.length && presets) {
const presetValue = dedupSort(presets.testMatch).join('::')
else if (migratedConfig.testMatch && migratedConfig.testMatch.length && preset) {
const presetValue = dedupSort(preset.value.testMatch).join('::')
const migratedValue = dedupSort(migratedConfig.testMatch).join('::')
if (presetValue === migratedValue) {
delete migratedConfig.testMatch
Expand All @@ -120,9 +119,9 @@ export const run: CliCommand = async (args: Arguments /*, logger: Logger*/) => {
}
// check if it's the same as the preset's one
if (
presets &&
preset &&
migratedConfig.transform &&
stringifyJson(migratedConfig.transform) === stringifyJson(presets.transform)
stringifyJson(migratedConfig.transform) === stringifyJson(preset.value.transform)
) {
delete migratedConfig.transform
}
Expand Down Expand Up @@ -154,10 +153,10 @@ No migration needed for given Jest configuration
// If it is the case, you can safely remove the "testMatch" from what I've migrated.
// `)
// }
if (presets && migratedConfig.transform) {
if (preset && migratedConfig.transform) {
footNotes.push(`
I couldn't check if your "transform" value is the same as mine which is: ${stringify(
presets.transform,
preset.value.transform,
undefined,
' ',
)}
Expand Down Expand Up @@ -197,7 +196,7 @@ function cleanupConfig(config: jest.InitialOptions): void {
config.testMatch = dedupSort(config.testMatch)
if (config.testMatch.length === 0) delete config.testMatch
}
if (config.preset === DEFAULT_PRESET) config.preset = 'ts-jest'
if (config.preset === JestPresetNames.default) config.preset = defaults.name
}

function dedupSort(arr: any[]) {
Expand All @@ -220,7 +219,8 @@ Arguments:
the "jest" property.
Options:
--allow-js ts-jest will be used to process JS files as well
--js ts|babel Process .js files with ts-jest if 'ts' or with
babel-jest if 'babel'
--no-jest-preset Disable the use of Jest presets
`)
}
55 changes: 55 additions & 0 deletions src/cli/helpers/presets.ts
@@ -0,0 +1,55 @@
import { TsJestPresets } from '../../types'

/** @internal */
export enum JestPresetNames {
default = 'ts-jest/presets/default',
jsWithTs = 'ts-jest/presets/js-with-ts',
jsWIthBabel = 'ts-jest/presets/js-with-babel',
}

/** @internal */
export interface TsJestPresetDescriptor {
name: string
fullName: string
label: string
jsVarName: string
value: TsJestPresets
isDefault: boolean
jsImport(varName?: string): string
}

const definePreset = (fullName: string): TsJestPresetDescriptor => ({
fullName,
get name() {
return this.isDefault ? 'ts-jest' : fullName
},
get label() {
return fullName.split('/').pop()!
},
get jsVarName() {
return this.isDefault
? 'defaults'
: fullName
.split('/')
.pop()!
.replace(/\-([a-z])/g, (_, l) => l.toUpperCase())
},
get value() {
return require(`../../../${fullName.replace(/^ts-jest\//, '')}/jest-preset`)
},
jsImport(varName = 'tsjPreset') {
return `const { ${this.jsVarName}: ${varName} } = require('${this.fullName}')`
},
get isDefault() {
return fullName === JestPresetNames.default
},
})

/** @internal */
export const allPresets: Record<JestPresetNames, TsJestPresetDescriptor> = {} as any
/** @internal */
export const defaults = (allPresets[JestPresetNames.default] = definePreset(JestPresetNames.default))
/** @internal */
export const jsWithTs = (allPresets[JestPresetNames.jsWithTs] = definePreset(JestPresetNames.jsWithTs))
/** @internal */
export const jsWIthBabel = (allPresets[JestPresetNames.jsWIthBabel] = definePreset(JestPresetNames.jsWIthBabel))
13 changes: 13 additions & 0 deletions src/cli/index.ts
Expand Up @@ -20,8 +20,21 @@ async function cli(args: string[]): Promise<void> {
count: ['verbose'],
alias: { verbose: ['v'] },
default: { jestPreset: true, verbose: 0 },
coerce: {
js(val: string) {
const res = val.trim().toLowerCase()
if (!['babel', 'ts'].includes(res)) throw new Error(`The 'js' option must be 'babel' or 'ts', given: '${val}'.`)
return res
},
},
})

// deprecated
if (parsedArgv.allowJs != null) {
if (parsedArgv.js) throw new Error(`The 'allowJs' and 'js' options cannot be set together.`)
parsedArgv.js = parsedArgv.allowJs ? 'ts' : undefined
}

let command = parsedArgv._.shift() as string
const isHelp = command === 'help'
if (isHelp) command = parsedArgv._.shift() as string
Expand Down

0 comments on commit 68abcfb

Please sign in to comment.