Skip to content

Commit

Permalink
feat(transform): pass config options through to transformer
Browse files Browse the repository at this point in the history
  • Loading branch information
SimenB committed Dec 7, 2020
1 parent 2928bb7 commit 19e2a28
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 36 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Expand Up @@ -13,6 +13,7 @@
- `[jest-runner]` [**BREAKING**] Run transforms over `runnner` ([#8823](https://github.com/facebook/jest/pull/8823))
- `[jest-runner]` [**BREAKING**] Run transforms over `testRunnner` ([#8823](https://github.com/facebook/jest/pull/8823))
- `[jest-runtime, jest-transform]` share `cacheFS` between runtime and transformer ([#10901](https://github.com/facebook/jest/pull/10901))
- `[jest-transform]` Pass config options defined in Jest's config to transformer's `process` and `getCacheKey` functions ([#10926](https://github.com/facebook/jest/pull/10926))

### Fixes

Expand Down Expand Up @@ -45,6 +46,7 @@
- `[*]` [**BREAKING**] Only support Node LTS releases and Node 15 ([#10685](https://github.com/facebook/jest/pull/10685))
- `[*]` [**BREAKING**] Add `exports` field to all `package.json`s ([#9921](https://github.com/facebook/jest/pull/9921))
- `[*]` Make it easier for Jest's packages to use the VM escape hatch ([#10824](https://github.com/facebook/jest/pull/10824))
- `[*]` [**BREAKING**] Remove deprecated `mapCoverage` ([#9968](https://github.com/facebook/jest/pull/9968))
- `[jest-config]` [**BREAKING**] Remove `enabledTestsMap` config, use `filter` instead ([#10787](https://github.com/facebook/jest/pull/10787))
- `[jest-console]` [**BREAKING**] Move `root` into `config` and take `GlobalConfig` as mandatory parameter for `getConsoleOutput` ([#10126](https://github.com/facebook/jest/pull/10126))
- `[jest-fake-timers]` Clarify global behavior of `jest.useFakeTimers` and `jest.useRealTimers` ([#10867](https://github.com/facebook/jest/pull/10867))
Expand All @@ -59,7 +61,6 @@
- `[jest-runtime]` [**BREAKING**] Remove deprecated and unnused `getSourceMapInfo` from Runtime ([#9969](https://github.com/facebook/jest/pull/9969))
- `[jest-util]` No longer checking `enumerable` when adding `process.domain` ([#10862](https://github.com/facebook/jest/pull/10862))
- `[jest-validate]` [**BREAKING**] Remove `recursiveBlacklist ` option in favor of previously introduced `recursiveDenylist` ([#10650](https://github.com/facebook/jest/pull/10650))
- `[*]` [**BREAKING**] Remove deprecated `mapCoverage` ([#9968](https://github.com/facebook/jest/pull/9968))

### Performance

Expand Down
8 changes: 5 additions & 3 deletions docs/CodeTransformation.md
Expand Up @@ -35,17 +35,17 @@ interface Transformer<OptionType = unknown> {
getCacheKey?: (
sourceText: string,
sourcePath: string,
options: TransformOptions,
options: TransformOptions<OptionType>,
) => string;

process: (
sourceText: string,
sourcePath: string,
options: TransformOptions,
options: TransformOptions<OptionType>,
) => TransformedSource;
}

interface TransformOptions {
interface TransformOptions<OptionType> {
/**
* If a transformer does module resolution and reads files, it should populate `cacheFS` so that
* Jest avoids reading the same files again, improving performance. `cacheFS` stores entries of
Expand All @@ -61,6 +61,8 @@ interface TransformOptions {
supportsExportNamespaceFrom: boolean;
supportsStaticESM: boolean;
supportsTopLevelAwait: boolean;
/** the options passed through Jest's config by the user */
transformerConfig: OptionType;
}

type TransformedSource =
Expand Down
10 changes: 5 additions & 5 deletions packages/babel-jest/src/index.ts
Expand Up @@ -50,7 +50,7 @@ const createTransformer: CreateTransformer = userOptions => {
function loadBabelConfig(
cwd: Config.Path,
filename: Config.Path,
transformOptions?: JestTransformOptions,
transformOptions: JestTransformOptions,
): PartialConfig {
// `cwd` first to allow incoming options to override it
const babelConfig = loadPartialConfig({
Expand All @@ -59,16 +59,16 @@ const createTransformer: CreateTransformer = userOptions => {
caller: {
...options.caller,
supportsDynamicImport:
transformOptions?.supportsDynamicImport ??
transformOptions.supportsDynamicImport ??
options.caller.supportsDynamicImport,
supportsExportNamespaceFrom:
transformOptions?.supportsExportNamespaceFrom ??
transformOptions.supportsExportNamespaceFrom ??
options.caller.supportsExportNamespaceFrom,
supportsStaticESM:
transformOptions?.supportsStaticESM ??
transformOptions.supportsStaticESM ??
options.caller.supportsStaticESM,
supportsTopLevelAwait:
transformOptions?.supportsTopLevelAwait ??
transformOptions.supportsTopLevelAwait ??
options.caller.supportsTopLevelAwait,
},
filename,
Expand Down
3 changes: 3 additions & 0 deletions packages/jest-repl/src/cli/repl.ts
Expand Up @@ -15,6 +15,7 @@ import type {Transformer} from '@jest/transform';
import type {Config} from '@jest/types';

let transformer: Transformer;
let transformerConfig: unknown;

const evalCommand: repl.REPLEval = (
cmd: string,
Expand All @@ -37,6 +38,7 @@ const evalCommand: repl.REPLEval = (
supportsExportNamespaceFrom: false,
supportsStaticESM: false,
supportsTopLevelAwait: false,
transformerConfig,
},
);
cmd =
Expand Down Expand Up @@ -69,6 +71,7 @@ if (jestProjectConfig.transform) {
for (let i = 0; i < jestProjectConfig.transform.length; i++) {
if (new RegExp(jestProjectConfig.transform[i][0]).test('foobar.js')) {
transformerPath = jestProjectConfig.transform[i][1];
transformerConfig = jestProjectConfig.transform[i][2];
break;
}
}
Expand Down
47 changes: 28 additions & 19 deletions packages/jest-transform/src/ScriptTransformer.ts
Expand Up @@ -67,7 +67,10 @@ export default class ScriptTransformer {
private readonly _cache: ProjectCache;
private readonly _cacheFS: StringMap;
private readonly _config: Config.ProjectConfig;
private readonly _transformCache: Map<Config.Path, Transformer>;
private readonly _transformCache: Map<
Config.Path,
{transformer: Transformer; transformerConfig: unknown}
>;
private readonly _transformConfigCache: Map<Config.Path, unknown>;

constructor(
Expand Down Expand Up @@ -102,7 +105,8 @@ export default class ScriptTransformer {
options: ReducedTransformOptions,
): string {
const configString = this._cache.configString;
const transformer = this._getTransformer(filename);
const {transformer, transformerConfig = {}} =
this._getTransformer(filename) || {};

if (transformer && typeof transformer.getCacheKey === 'function') {
return createHash('md5')
Expand All @@ -112,6 +116,7 @@ export default class ScriptTransformer {
cacheFS: this._cacheFS,
config: this._config,
configString,
transformerConfig,
}),
)
.update(CACHE_VERSION)
Expand Down Expand Up @@ -181,28 +186,30 @@ export default class ScriptTransformer {
return null;
}

const transformer = this._transformCache.get(transformPath);
if (transformer) {
return transformer;
const cached = this._transformCache.get(transformPath);
if (cached) {
return cached;
}

let transform: Transformer = require(transformPath);
let transformer: Transformer = require(transformPath);

if (!transform) {
if (!transformer) {
throw new TypeError('Jest: a transform must export something.');
}
const transformerConfig = this._transformConfigCache.get(transformPath);
if (typeof transform.createTransformer === 'function') {
transform = transform.createTransformer(transformerConfig);
const transformerConfig =
this._transformConfigCache.get(transformPath) || {};
if (typeof transformer.createTransformer === 'function') {
transformer = transformer.createTransformer(transformerConfig);
}
if (typeof transform.process !== 'function') {
if (typeof transformer.process !== 'function') {
throw new TypeError(
'Jest: a transform must export a `process` function.',
);
}
this._transformCache.set(transformPath, transform);
const res = {transformer, transformerConfig};
this._transformCache.set(transformPath, res);

return transform;
return res;
}

private _instrumentFile(
Expand Down Expand Up @@ -262,18 +269,19 @@ export default class ScriptTransformer {
options: ReducedTransformOptions,
): TransformResult {
const filename = tryRealpath(filepath);
const transform = this._getTransformer(filename);
const {transformer, transformerConfig = {}} =
this._getTransformer(filename) || {};
const cacheFilePath = this._getFileCachePath(filename, content, options);
let sourceMapPath: Config.Path | null = cacheFilePath + '.map';
// Ignore cache if `config.cache` is set (--no-cache)
let code = this._config.cache ? readCodeCacheFile(cacheFilePath) : null;

const shouldCallTransform = transform && this.shouldTransform(filename);
const shouldCallTransform = transformer && this.shouldTransform(filename);

// That means that the transform has a custom instrumentation
// logic and will handle it based on `config.collectCoverage` option
const transformWillInstrument =
shouldCallTransform && transform && transform.canInstrument;
shouldCallTransform && transformer && transformer.canInstrument;

if (code) {
// This is broken: we return the code, and a path for the source map
Expand All @@ -292,12 +300,13 @@ export default class ScriptTransformer {
map: null,
};

if (transform && shouldCallTransform) {
const processed = transform.process(content, filename, {
if (transformer && shouldCallTransform) {
const processed = transformer.process(content, filename, {
...options,
cacheFS: this._cacheFS,
config: this._config,
configString: this._cache.configString,
transformerConfig,
});

if (typeof processed === 'string') {
Expand Down Expand Up @@ -343,7 +352,7 @@ export default class ScriptTransformer {
*
*/
const shouldEmitSourceMaps =
(transform != null && map != null) || transform == null;
(transformer != null && map != null) || transformer == null;

const instrumented = this._instrumentFile(
filename,
Expand Down
Expand Up @@ -663,7 +663,10 @@ describe('ScriptTransformer', () => {
});

it('passes expected transform options to getCacheKey', () => {
config = {...config, transform: [['\\.js$', 'test_preprocessor', {}]]};
config = {
...config,
transform: [['\\.js$', 'test_preprocessor', {configKey: 'configValue'}]],
};
const scriptTransformer = new ScriptTransformer(config);

scriptTransformer.transform(
Expand Down

0 comments on commit 19e2a28

Please sign in to comment.