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 custom options in custom transformers #1966

Merged
merged 2 commits into from Sep 18, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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