Skip to content

Commit

Permalink
feat(config): allow custom options in custom transformers (#1966)
Browse files Browse the repository at this point in the history
Closes #1942

Co-authored-by: Long Ho <holevietlong@gmail.com>
  • Loading branch information
ahnpnl and longlho committed Sep 18, 2020
1 parent 05d9b8b commit 1452ce4
Show file tree
Hide file tree
Showing 9 changed files with 275 additions and 37 deletions.
69 changes: 58 additions & 11 deletions docs/user/config/astTransformers.md
Expand Up @@ -7,13 +7,15 @@ TypeScript AST transformers and provide them to `ts-jest` to include into compil

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` ).
- `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

#### Basic Transformers

<div class="row"><div class="col-md-6" markdown="block">

```js
Expand All @@ -25,9 +27,52 @@ module.exports = {
astTransformers: {
before: ['my-custom-transformer'],
},
},
},
}
```

</div><div class="col-md-6" markdown="block">

```js
// OR package.json
{
// [...]
"jest": {
"globals": {
"ts-jest": {
astTransformers: {
"before": ["my-custom-transformer"]
}
}
}
}
};
}
```

</div></div>

#### Configuring transformers with options

<div class="row"><div class="col-md-6" markdown="block">

```js
// jest.config.js
module.exports = {
// [...]
globals: {
'ts-jest': {
astTransformers: {
before: [
{
path: 'my-custom-transformer-that-needs-extra-opts',
options: {}, // extra options to pass to transformers here
},
],
},
},
},
}
```

</div><div class="col-md-6" markdown="block">
Expand All @@ -40,7 +85,10 @@ module.exports = {
"globals": {
"ts-jest": {
astTransformers: {
"before": ["my-custom-transformer"]
"before": [{
path: 'my-custom-transformer-that-needs-extra-opts',
options: {} // extra options to pass to transformers here
}]
}
}
}
Expand All @@ -55,9 +103,9 @@ module.exports = {
`ts-jest` is able to expose transformers for public usage to provide the possibility to opt-in/out for users. Currently
the exposed transformers are:

- `path-mapping` convert alias import/export to relative import/export path base on `paths` in `tsconfig`.
This transformer works similar to `moduleNameMapper` in `jest.config.js`. When using this transformer, one might not need
`moduleNameMapper` anymore.
- `path-mapping` convert alias import/export to relative import/export path base on `paths` in `tsconfig`.
This transformer works similar to `moduleNameMapper` in `jest.config.js`. When using this transformer, one might not need
`moduleNameMapper` anymore.

#### Example of opt-in transformers

Expand All @@ -72,9 +120,9 @@ module.exports = {
astTransformers: {
before: ['ts-jest/dist/transformers/path-mapping'],
},
}
}
};
},
},
}
```

</div><div class="col-md-6" markdown="block">
Expand All @@ -97,7 +145,6 @@ module.exports = {

</div></div>


### Writing custom TypeScript AST 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.
18 changes: 18 additions & 0 deletions e2e/__cases__/ast-transformers/with-extra-options/foo.js
@@ -0,0 +1,18 @@
const { LogContexts, LogLevels } = require('bs-logger')

function factory(cs, extraOpts = Object.create(null)) {
const logger = cs.logger.child({ namespace: 'dummy-transformer' })
const ts = cs.compilerModule
logger.debug('Dummy transformer with extra options', JSON.stringify(extraOpts))

function createVisitor(_ctx, _sf) {
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
@@ -0,0 +1,5 @@
const a = 1;

it('should pass', () => {
expect(a).toEqual(1);
})
19 changes: 19 additions & 0 deletions e2e/__tests__/__snapshots__/ast-transformers.test.ts.snap
@@ -0,0 +1,19 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`AST transformers with extra options should pass using template "default" 1`] = `
Array [
"[level:20] Dummy transformer with extra options {\\"foo\\":\\"bar\\"}",
]
`;

exports[`AST transformers with extra options should pass using template "with-babel-7" 1`] = `
Array [
"[level:20] Dummy transformer with extra options {\\"foo\\":\\"bar\\"}",
]
`;

exports[`AST transformers with extra options should pass using template "with-babel-7-string-config" 1`] = `
Array [
"[level:20] Dummy transformer with extra options {\\"foo\\":\\"bar\\"}",
]
`;
38 changes: 38 additions & 0 deletions e2e/__tests__/ast-transformers.test.ts
@@ -0,0 +1,38 @@
import { configureTestCase } from '../__helpers__/test-case'
import { allValidPackageSets } from '../__helpers__/templates'
import { existsSync } from "fs"
import { LogContexts, LogLevels } from 'bs-logger'

describe('AST transformers', () => {
describe('with extra options', () => {
const testCase = configureTestCase('ast-transformers/with-extra-options', {
env: { TS_JEST_LOG: 'ts-jest.log' },
tsJestConfig: {
astTransformers: {
before: [{
path: require.resolve('../__cases__/ast-transformers/with-extra-options/foo'),
options: {
foo: 'bar',
},
}],
},
},
})

testCase.runWithTemplates(allValidPackageSets, 0, (runTest, { testLabel }) => {
it(testLabel, () => {
const result = runTest()
expect(result.status).toBe(0)
expect(existsSync(result.logFilePath)).toBe(true)
const filteredEntries = result.logFileEntries
// keep only debug and above
.filter(m => (m.context[LogContexts.logLevel] || 0) >= LogLevels.debug)
// simplify entries
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
.map(e => result.normalize(`[level:${e.context[LogContexts.logLevel]}] ${e.message}`))
.filter(logging => logging.includes('Dummy transformer with extra options'))
expect(filteredEntries).toMatchSnapshot()
})
})
})
})
11 changes: 11 additions & 0 deletions src/config/__snapshots__/config-set.spec.ts.snap
Expand Up @@ -355,3 +355,14 @@ exports[`tsJest transformers should display deprecation warning message when con
"[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
"
`;

exports[`tsJest transformers should support transformers with options 1`] = `
Array [
Object {
"options": Object {
"foo": 1,
},
"path": Any<String>,
},
]
`;
31 changes: 31 additions & 0 deletions src/config/config-set.spec.ts
Expand Up @@ -161,6 +161,37 @@ describe('tsJest', () => {
expect(logger.target.lines[1]).toMatchSnapshot()
})

it('should support transformers with options', () => {
const cs = createConfigSet({
jestConfig: {
rootDir: 'src',
cwd: 'src',
globals: {
'ts-jest': {
astTransformers: {
before: [
{
path: 'dummy-transformer',
options: {
foo: 1,
},
},
],
},
},
},
} as any,
logger,
resolve: null,
})

expect(cs.tsJest.transformers.before).toMatchSnapshot([
{
path: expect.any(String),
},
])
})

it.each([
{},
{
Expand Down

0 comments on commit 1452ce4

Please sign in to comment.