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(transformers): add path-mapping custom AST transformer #1927

Merged
merged 1 commit into from
Sep 4, 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
2 changes: 2 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ module.exports = {
'getter-return': 'warn',
'guard-for-in': 'error',
'id-match': 'error',
'jest/valid-title': 'off',
'jest/no-conditional-expect': 'off',
'jsdoc/check-alignment': 'error',
'jsdoc/check-indentation': 'error',
'jsdoc/newline-after-description': 'warn',
Expand Down
48 changes: 48 additions & 0 deletions docs/user/config/astTransformers.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,54 @@ module.exports = {

</div></div>

### Public transformers

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

#### Example of opt-in transformers

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

```js
// jest.config.js
module.exports = {
// [...]
globals: {
'ts-jest': {
astTransformers: {
before: ['ts-jest/dist/transformers/path-mapping'],
},
}
}
};
```

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

```js
// OR package.json
{
// [...]
"jest": {
"globals": {
"ts-jest": {
astTransformers: {
"before": ["ts-jest/dist/transformers/path-mapping"]
}
}
}
}
}
```

</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.
7 changes: 7 additions & 0 deletions e2e/__cases__/path-mapping/direct-import.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { getWelcomeMessage } from '@share/foo'

test('should return welcome message', () => {
const userName = 'github-user'

expect(getWelcomeMessage(userName)).toEqual(`yolo ${userName}`)
})
6 changes: 6 additions & 0 deletions e2e/__cases__/path-mapping/dynamic-import.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
test('should return welcome message', async () => {
const userName = 'github-user'
const foo = await import('@share/foo')

expect(foo.getWelcomeMessage(userName)).toEqual(`yolo ${userName}`)
})
7 changes: 7 additions & 0 deletions e2e/__cases__/path-mapping/export.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { getWelcomeMessage } from '@share/export'

test('should return welcome message', async () => {
const userName = ''

expect(getWelcomeMessage(userName)).toEqual(`yolo ${userName}`)
})
7 changes: 7 additions & 0 deletions e2e/__cases__/path-mapping/import-default.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import foo from '@share/foo'

test('should return welcome message', () => {
const userName = 'github-user'

expect(foo(userName)).toBe(`yolo ${userName}`)
})
7 changes: 7 additions & 0 deletions e2e/__cases__/path-mapping/import-legacy.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import foo = require('@share/foo')

test('should return welcome message', () => {
const userName = 'github-user'

expect(foo.getWelcomeMessage(userName)).toEqual(`yolo ${userName}`)
})
7 changes: 7 additions & 0 deletions e2e/__cases__/path-mapping/import-require.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const foo = require('@share/foo')

test('should return welcome message', () => {
const userName = 'github-user'

expect(foo.getWelcomeMessage(userName)).toEqual(`yolo ${userName}`)
})
7 changes: 7 additions & 0 deletions e2e/__cases__/path-mapping/import-star.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as foo from '@share/foo'

test('should return welcome message', () => {
const userName = 'github-user'

expect(foo.getWelcomeMessage(userName)).toEqual(`yolo ${userName}`)
})
9 changes: 9 additions & 0 deletions e2e/__cases__/path-mapping/import-type.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type { Foo } from '@share/foo'

test('should work', () => {
const a: Foo = {
bar: 1,
}

expect(a).toBeTruthy()
})
1 change: 1 addition & 0 deletions e2e/__cases__/path-mapping/share/export.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { getWelcomeMessage } from '@share/foo'
13 changes: 13 additions & 0 deletions e2e/__cases__/path-mapping/share/foo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export function getWelcomeMessage(username: string): string {
return `yolo ${username}`;
}

function getMessage(username: string) {
return getWelcomeMessage(username)
}

export interface Foo {
bar: number
}

export default getMessage
12 changes: 12 additions & 0 deletions e2e/__cases__/path-mapping/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "es5",
"baseUrl": ".",
"paths": {
"@share/*": ["share/*"]
}
},
"exclude": [
"node_modules"
]
}
2 changes: 1 addition & 1 deletion e2e/__external-repos__/custom-typings/jest.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testEnvironment: 'node'
}
2 changes: 2 additions & 0 deletions e2e/__external-repos__/path-mapping/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.idea
node_modules
9 changes: 9 additions & 0 deletions e2e/__external-repos__/path-mapping/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# A project to demonstrate how to setup `ts-jest` only to work together with `jest`

## Installation
Run `yarn` to install dependencies

## Overview about configuration
The project contains:
- A `jest.config.js` which contains config for `ts-jest`.
- A `tsconfig.json` which contains config for `typescript`.
23 changes: 23 additions & 0 deletions e2e/__external-repos__/path-mapping/foo.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { isStoreOwner } from './foo';
import { getWelcomeMessage } from '@share/get-welcome-message';
import type { Foo } from '@share/typings'

describe('Test optional chaining', () => {
test(`should work`, () => {
expect(isStoreOwner({
isStoreOwner: false,
})).toEqual(false)
})

test(`test export *`, () => {
expect(getWelcomeMessage('foo')).toEqual('yolo foo')
})

test(`test import type`, () => {
const foo: Foo = {
bar: 1,
}

expect(foo).toBeTruthy()
})
});
5 changes: 5 additions & 0 deletions e2e/__external-repos__/path-mapping/foo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
interface User {
isStoreOwner: boolean
}

export const isStoreOwner = (user: User) => user?.isStoreOwner;
16 changes: 16 additions & 0 deletions e2e/__external-repos__/path-mapping/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// For a detailed explanation regarding each configuration property, visit:
// https://jestjs.io/docs/en/configuration.html
/** @typedef {import('ts-jest')} */
/** @type {import('@jest/types').Config.InitialOptions} */
module.exports = {
preset: 'ts-jest',
globals: {
'ts-jest': {
astTransformers: {
before: [
'ts-jest/dist/transformers/path-mapping'
]
}
}
}
};
14 changes: 14 additions & 0 deletions e2e/__external-repos__/path-mapping/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "ts-jest-example",
"version": "1.0.0",
"license": "MIT",
"devDependencies": {
"@types/jest": "26.x",
"jest": "26.x",
"ts-jest": "26.x",
"typescript": "~4.0.2"
},
"scripts": {
"test": "jest"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { getWelcomeMessage } from './get-welcome-message';

describe(`getWelcomeMessage()`, (): void => {
let username: string;

describe(`when the given username is a simple string`, (): void => {
beforeEach(
(): void => {
username = `C0ZEN`;
}
);

it(`should return a message for this username`, (): void => {
expect.assertions(1);

const result = getWelcomeMessage(username);

expect(result).toStrictEqual(`yolo C0ZEN`);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function getWelcomeMessage(username: string): string {
return `yolo ${username}`;
}
3 changes: 3 additions & 0 deletions e2e/__external-repos__/path-mapping/src/share/typings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface Foo {
bar: number
}
16 changes: 16 additions & 0 deletions e2e/__external-repos__/path-mapping/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"baseUrl": ".",
"declaration": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"paths": {
"@share/*": ["src/share/*"]
}
},
"exclude": [
"node_modules"
]
}