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): support after and afterDeclarations AST transformers #1831

Merged
merged 2 commits into from Jul 28, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 13 additions & 5 deletions docs/user/config/astTransformers.md
Expand Up @@ -5,7 +5,12 @@ title: AST transformers option
`ts-jest` by default does hoisting for a few `jest` methods via a TypeScript AST transformer. One can also create custom
TypeScript AST transformers and provide them to `ts-jest` to include into compilation process.

The option is `astTransformers` and it allows ones to specify which TypeScript AST transformers to use with `ts-jest`.
The option is `astTransformers` and it allows ones to specify which 3 types of TypeScript AST transformers to use with `ts-jest`:

- `before` means your transformers get run before TS ones, which means your transformers will get raw TS syntax
instead of transpiled syntax (e.g `import` instead of `require` or `define` ).
- `after` means your transformers get run after TS ones, which gets transpiled syntax.
- `afterDeclarations` means your transformers get run during `d.ts` generation phase, allowing you to transform output type declarations.

### Examples

Expand All @@ -17,7 +22,9 @@ module.exports = {
// [...]
globals: {
'ts-jest': {
astTransformers: ['my-custom-transformer'],
astTransformers: {
before: ['my-custom-transformer'],
},
}
}
};
Expand All @@ -32,7 +39,9 @@ module.exports = {
"jest": {
"globals": {
"ts-jest": {
astTransformers: ['my-custom-transformer'],
astTransformers: {
"before": ["my-custom-transformer"]
}
}
}
}
Expand All @@ -43,5 +52,4 @@ module.exports = {

### Writing custom TypeScript AST transformers

To write a custom TypeScript AST transformers, one can take a look at the one that `ts-jest` is using at
https://github.com/kulshekhar/ts-jest/tree/master/src/transformers
To write a custom TypeScript AST transformers, one can take a look at [the one](https://github.com/kulshekhar/ts-jest/tree/master/src/transformers) that `ts-jest` is using.
111 changes: 111 additions & 0 deletions e2e/__tests__/__snapshots__/logger.test.ts.snap
Expand Up @@ -124,6 +124,117 @@ Array [
]
`;

exports[`ts-jest logging deprecation warning with astTransformers config as an object should pass using template "default" 1`] = `
√ jest
↳ exit code: 0
===[ STDOUT ]===================================================================

===[ STDERR ]===================================================================
PASS ./Hello.spec.ts
Hello Class
√ should create a new Hello

Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: XXs
Ran all test suites.
================================================================================
`;

exports[`ts-jest logging deprecation warning with astTransformers config as an object should pass using template "with-babel-7" 1`] = `
√ jest
↳ exit code: 0
===[ STDOUT ]===================================================================

===[ STDERR ]===================================================================
PASS ./Hello.spec.ts
Hello Class
√ should create a new Hello

Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: XXs
Ran all test suites.
================================================================================
`;

exports[`ts-jest logging deprecation warning with astTransformers config as an object should pass using template "with-babel-7-string-config" 1`] = `
√ jest
↳ exit code: 0
===[ STDOUT ]===================================================================

===[ STDERR ]===================================================================
PASS ./Hello.spec.ts
Hello Class
√ should create a new Hello

Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: XXs
Ran all test suites.
================================================================================
`;

exports[`ts-jest logging deprecation warning with astTransformers config as string array should pass using template "default" 1`] = `
√ jest
↳ exit code: 0
===[ STDOUT ]===================================================================

===[ STDERR ]===================================================================
ts-jest[config] (WARN) The configuration for astTransformers as string[] is deprecated and will be removed in ts-jest 27. Please define your custom AST transformers in a form of an object. More information you can check online documentation https://kulshekhar.github.io/ts-jest/user/config/astTransformers
PASS ./Hello.spec.ts
Hello Class
√ should create a new Hello

Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: XXs
Ran all test suites.
================================================================================
`;

exports[`ts-jest logging deprecation warning with astTransformers config as string array should pass using template "with-babel-7" 1`] = `
√ jest
↳ exit code: 0
===[ STDOUT ]===================================================================

===[ STDERR ]===================================================================
ts-jest[config] (WARN) The configuration for astTransformers as string[] is deprecated and will be removed in ts-jest 27. Please define your custom AST transformers in a form of an object. More information you can check online documentation https://kulshekhar.github.io/ts-jest/user/config/astTransformers
PASS ./Hello.spec.ts
Hello Class
√ should create a new Hello

Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: XXs
Ran all test suites.
================================================================================
`;

exports[`ts-jest logging deprecation warning with astTransformers config as string array should pass using template "with-babel-7-string-config" 1`] = `
√ jest
↳ exit code: 0
===[ STDOUT ]===================================================================

===[ STDERR ]===================================================================
ts-jest[config] (WARN) The configuration for astTransformers as string[] is deprecated and will be removed in ts-jest 27. Please define your custom AST transformers in a form of an object. More information you can check online documentation https://kulshekhar.github.io/ts-jest/user/config/astTransformers
PASS ./Hello.spec.ts
Hello Class
√ should create a new Hello

Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: XXs
Ran all test suites.
================================================================================
`;

exports[`ts-jest logging with unsupported version test with TS_JEST_DISABLE_VER_CHECKER is not set in process.env should pass using template "with-unsupported-version" 1`] = `
√ jest
↳ exit code: 0
Expand Down
36 changes: 35 additions & 1 deletion e2e/__tests__/logger.test.ts
Expand Up @@ -47,7 +47,7 @@ describe('ts-jest logging', () => {
const filteredEntries = result.logFileEntries
// keep only debug and above
.filter(m => (m.context[LogContexts.logLevel] || 0) >= LogLevels.debug)
// simplify entires
// simplify entries
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
.map(e => result.normalize(`[level:${e.context[LogContexts.logLevel]}] ${e.message}`))
expect(filteredEntries).toMatchSnapshot()
Expand Down Expand Up @@ -90,4 +90,38 @@ describe('ts-jest logging', () => {
})
})
}

describe('deprecation warning', () => {
describe('with astTransformers config as string array', () => {
const testCase = configureTestCase('simple', {
tsJestConfig: {
astTransformers: []
}
})

testCase.runWithTemplates(allValidPackageSets, 0, (runTest, { testLabel }) => {
it(testLabel, () => {
const result = runTest()
expect(result.status).toBe(0)
expect(result).toMatchSnapshot()
})
})
})

describe('with astTransformers config as an object', () => {
const testCase = configureTestCase('simple', {
tsJestConfig: {
astTransformers: {}
}
})

testCase.runWithTemplates(allValidPackageSets, 0, (runTest, { testLabel }) => {
it(testLabel, () => {
const result = runTest()
expect(result.status).toBe(0)
expect(result).toMatchSnapshot()
})
})
})
})
})
2 changes: 1 addition & 1 deletion src/__helpers__/fakers.ts
Expand Up @@ -16,7 +16,7 @@ export function tsJestConfig(options?: Partial<TsJestConfig>): TsJestConfig {
return {
isolatedModules: false,
compiler: 'typescript',
transformers: [],
transformers: options?.transformers ?? Object.create(null),
babelConfig: undefined,
tsConfig: undefined,
packageJson: undefined,
Expand Down
17 changes: 17 additions & 0 deletions src/__mocks__/dummy-transformer.js
@@ -0,0 +1,17 @@
const { LogContexts, LogLevels } = require('bs-logger')

function factory(cs) {
const logger = cs.logger.child({ namespace: 'dummy-transformer' })
const ts = cs.compilerModule

function createVisitor(_ctx, _) {
return (node) => node
}

return (ctx) =>
logger.wrap({ [LogContexts.logLevel]: LogLevels.debug, call: null }, 'visitSourceFileNode(): dummy', (sf) =>
ts.visitNode(sf, createVisitor(ctx, sf))
)
}

exports.factory = factory
4 changes: 2 additions & 2 deletions src/compiler/instance.ts
Expand Up @@ -15,7 +15,7 @@ const SOURCE_MAPPING_PREFIX = 'sourceMappingURL='
/**
* Update the output remapping the source map.
*/
function updateOutput(outputText: string, normalizedFileName: string, sourceMap: string) {
function updateOutput(outputText: string, normalizedFileName: string, sourceMap: string): string {
const base64Map = Buffer.from(updateSourceMap(sourceMap, normalizedFileName), 'utf8').toString('base64')
const sourceMapContent = `data:application/json;charset=utf-8;base64,${base64Map}`

Expand Down Expand Up @@ -45,7 +45,7 @@ const compileAndUpdateOutput = (compileFn: CompileFn, logger: Logger) => (
code: string,
fileName: string,
lineOffset?: number,
) => {
): string => {
logger.debug({ fileName }, 'compileAndUpdateOutput(): get compile output')

const [value, sourceMap] = compileFn(code, fileName, lineOffset)
Expand Down
16 changes: 15 additions & 1 deletion src/compiler/language-service.ts
Expand Up @@ -7,12 +7,26 @@ import * as _ts from 'typescript'

import type { ConfigSet } from '../config/config-set'
import { LINE_FEED } from '../constants'
import { CompilerInstance, MemoryCache, SourceOutput, TSFile } from '../types'
import { CompilerInstance, SourceOutput } from '../types'
import { Errors, interpolate } from '../util/messages'

import { parse, stringify } from '../util/json'
import { sha1 } from '../util/sha1'

/** where key is filepath */
type TSFiles = Map<string, TSFile>

interface TSFile {
text?: string
output?: string
version: number
}

interface MemoryCache {
resolvedModules: Map<string, string[]>
files: TSFiles
}

function doTypeChecking(
configs: ConfigSet,
diagnosedFiles: string[],
Expand Down
50 changes: 47 additions & 3 deletions src/config/__snapshots__/config-set.spec.ts.snap
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`cacheKey should be a string 1`] = `"{\\"digest\\":\\"a0d51ca854194df8191d0e65c0ca4730f510f332\\",\\"jest\\":{\\"__backported\\":true,\\"globals\\":{}},\\"projectDepVersions\\":{\\"dev\\":\\"1.2.5\\",\\"opt\\":\\"1.2.3\\",\\"peer\\":\\"1.2.4\\",\\"std\\":\\"1.2.6\\"},\\"transformers\\":[\\"hoisting-jest-mock@1\\"],\\"tsJest\\":{\\"compiler\\":\\"typescript\\",\\"diagnostics\\":{\\"ignoreCodes\\":[6059,18002,18003],\\"pretty\\":true,\\"throws\\":true},\\"isolatedModules\\":false,\\"packageJson\\":{\\"kind\\":\\"file\\"},\\"transformers\\":[],\\"tsConfig\\":{\\"kind\\":\\"file\\",\\"value\\":\\"\\"}},\\"tsconfig\\":{\\"options\\":{\\"configFilePath\\":\\"\\",\\"declaration\\":false,\\"inlineSourceMap\\":false,\\"inlineSources\\":true,\\"module\\":1,\\"noEmit\\":false,\\"removeComments\\":false,\\"sourceMap\\":true,\\"target\\":1,\\"types\\":[]},\\"raw\\":{\\"compileOnSave\\":false,\\"compilerOptions\\":{\\"composite\\":true,\\"declaration\\":true,\\"types\\":[]},\\"exclude\\":[\\"foo/**/*\\"],\\"include\\":[\\"bar/**/*\\"]}}}"`;
exports[`cacheKey should be a string 1`] = `"{\\"digest\\":\\"a0d51ca854194df8191d0e65c0ca4730f510f332\\",\\"jest\\":{\\"__backported\\":true,\\"globals\\":{}},\\"projectDepVersions\\":{\\"dev\\":\\"1.2.5\\",\\"opt\\":\\"1.2.3\\",\\"peer\\":\\"1.2.4\\",\\"std\\":\\"1.2.6\\"},\\"transformers\\":[\\"hoisting-jest-mock@1\\"],\\"tsJest\\":{\\"compiler\\":\\"typescript\\",\\"diagnostics\\":{\\"ignoreCodes\\":[6059,18002,18003],\\"pretty\\":true,\\"throws\\":true},\\"isolatedModules\\":false,\\"packageJson\\":{\\"kind\\":\\"file\\"},\\"transformers\\":{},\\"tsConfig\\":{\\"kind\\":\\"file\\",\\"value\\":\\"\\"}},\\"tsconfig\\":{\\"options\\":{\\"configFilePath\\":\\"\\",\\"declaration\\":false,\\"inlineSourceMap\\":false,\\"inlineSources\\":true,\\"module\\":1,\\"noEmit\\":false,\\"removeComments\\":false,\\"sourceMap\\":true,\\"target\\":1,\\"types\\":[]},\\"raw\\":{\\"compileOnSave\\":false,\\"compilerOptions\\":{\\"composite\\":true,\\"declaration\\":true,\\"types\\":[]},\\"exclude\\":[\\"foo/**/*\\"],\\"include\\":[\\"bar/**/*\\"]}}}"`;

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

Expand Down Expand Up @@ -67,7 +67,7 @@ Object {
"value": undefined,
},
"stringifyContentPathRegex": undefined,
"transformers": Array [],
"transformers": Object {},
"tsConfig": Object {
"kind": "file",
"value": "",
Expand Down Expand Up @@ -156,6 +156,45 @@ Array [
]
`;

exports[`tsCustomTransformers should return an object containing all resolved transformers 1`] = `
Object {
"before": Array [
[Function],
],
}
`;

exports[`tsCustomTransformers should return an object containing all resolved transformers 2`] = `
Object {
"before": Array [
[Function],
[Function],
],
}
`;

exports[`tsCustomTransformers should return an object containing all resolved transformers 3`] = `
Object {
"after": Array [
[Function],
],
"before": Array [
[Function],
],
}
`;

exports[`tsCustomTransformers should return an object containing all resolved transformers 4`] = `
Object {
"afterDeclarations": Array [
[Function],
],
"before": Array [
[Function],
],
}
`;

exports[`tsJest should return correct defaults 1`] = `
Object {
"babelConfig": undefined,
Expand All @@ -175,10 +214,15 @@ Object {
"value": undefined,
},
"stringifyContentPathRegex": undefined,
"transformers": Array [],
"transformers": Object {},
"tsConfig": Object {
"kind": "file",
"value": undefined,
},
}
`;

exports[`tsJest transformers should display deprecation warning message when config transformers is string array 1`] = `
"[level:40] The configuration for astTransformers as string[] is deprecated and will be removed in ts-jest 27. Please define your custom AST transformers in a form of an object. More information you can check online documentation https://kulshekhar.github.io/ts-jest/user/config/astTransformers
"
`;