ts-jest 26.2.0 → 26.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.ts-jest-digest CHANGED
@@ -1 +1 @@
1
- 3793ca0e5f06b7056a87f12d06ee54c5afb1dc2a
1
+ c0f7b076fbdbbcb07384ff15394a4e997771ae49
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ # [26.3.0](https://github.com/kulshekhar/ts-jest/compare/v26.2.0...v26.3.0) (2020-08-25)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **config:** compute cache key without reading `package.json` ([#1893](https://github.com/kulshekhar/ts-jest/issues/1893)) ([4875a58](https://github.com/kulshekhar/ts-jest/commit/4875a58345666e0407f9f5b3f95049ae2c9d056d)), closes [#1892](https://github.com/kulshekhar/ts-jest/issues/1892)
7
+
8
+
9
+ ### Features
10
+
11
+ * support TypeScript 4.0 ([#1889](https://github.com/kulshekhar/ts-jest/issues/1889)) ([f070e93](https://github.com/kulshekhar/ts-jest/commit/f070e9334a9cf31fa6f0d73b3f69d805be72601d))
12
+
13
+
14
+
1
15
  # [26.2.0](https://github.com/kulshekhar/ts-jest/compare/v26.1.4...v26.2.0) (2020-08-11)
2
16
 
3
17
 
@@ -1 +1,6 @@
1
+ /**
2
+ * This has been written quickly. While trying to improve I realised it'd be better to have it in Jest...
3
+ * ...and I saw a merged PR with `jest --init` tool!
4
+ * TODO: see what's the best path for this
5
+ */
1
6
  export {};
@@ -1,4 +1,9 @@
1
1
  "use strict";
2
+ /**
3
+ * This has been written quickly. While trying to improve I realised it'd be better to have it in Jest...
4
+ * ...and I saw a merged PR with `jest --init` tool!
5
+ * TODO: see what's the best path for this
6
+ */
2
7
  var __assign = (this && this.__assign) || function () {
3
8
  __assign = Object.assign || function(t) {
4
9
  for (var s, i = 1, n = arguments.length; i < n; i++) {
@@ -52,7 +57,10 @@ var fs_1 = require("fs");
52
57
  var json5_1 = require("json5");
53
58
  var path_1 = require("path");
54
59
  var presets_1 = require("../helpers/presets");
55
- exports.run = function (args) { return __awaiter(void 0, void 0, void 0, function () {
60
+ /**
61
+ * @internal
62
+ */
63
+ exports.run = function (args /* , logger: Logger */) { return __awaiter(void 0, void 0, void 0, function () {
56
64
  var file, filePath, name, isPackage, exists, pkgFile, hasPackage, _a, jestPreset, askedTsconfig, force, jsdom, tsconfig, pkgJson, jsFilesProcessor, shouldPostProcessWithBabel, preset, body, base, tsJestConf, content;
57
65
  return __generator(this, function (_b) {
58
66
  file = args._[0] || 'jest.config.js';
@@ -66,10 +74,13 @@ exports.run = function (args) { return __awaiter(void 0, void 0, void 0, functio
66
74
  tsconfig = askedTsconfig === 'tsconfig.json' ? undefined : askedTsconfig;
67
75
  pkgJson = hasPackage ? JSON.parse(fs_1.readFileSync(pkgFile, 'utf8')) : {};
68
76
  jsFilesProcessor = args.js, shouldPostProcessWithBabel = args.babel;
77
+ // set defaults for missing options
69
78
  if (jsFilesProcessor == null) {
79
+ // set default js files processor depending on whether the user wants to post-process with babel
70
80
  jsFilesProcessor = shouldPostProcessWithBabel ? 'babel' : undefined;
71
81
  }
72
82
  else if (shouldPostProcessWithBabel == null) {
83
+ // auto enables babel post-processing if the user wants babel to process js files
73
84
  shouldPostProcessWithBabel = jsFilesProcessor === 'babel';
74
85
  }
75
86
  if (jsFilesProcessor === 'babel') {
@@ -138,16 +149,20 @@ exports.run = function (args) { return __awaiter(void 0, void 0, void 0, functio
138
149
  content.push(' },');
139
150
  }
140
151
  content.push('};');
152
+ // join all together
141
153
  body = content.join('\n');
142
154
  }
143
155
  fs_1.writeFileSync(filePath, body);
144
156
  process.stderr.write("\nJest configuration written to \"" + filePath + "\".\n");
145
- return [2];
157
+ return [2 /*return*/];
146
158
  });
147
159
  }); };
160
+ /**
161
+ * @internal
162
+ */
148
163
  exports.help = function () { return __awaiter(void 0, void 0, void 0, function () {
149
164
  return __generator(this, function (_a) {
150
165
  process.stdout.write("\nUsage:\n ts-jest config:init [options] [<config-file>]\n\nArguments:\n <config-file> Can be a js or json Jest config file. If it is a\n package.json file, the configuration will be read from\n the \"jest\" property.\n Default: jest.config.js\n\nOptions:\n --force Discard any existing Jest config\n --js ts|babel Process .js files with ts-jest if 'ts' or with\n babel-jest if 'babel'\n --no-jest-preset Disable the use of Jest presets\n --tsconfig <file> Path to the tsconfig.json file\n --babel Pipe babel-jest after ts-jest\n --jsdom Use jsdom as test environment instead of node\n");
151
- return [2];
166
+ return [2 /*return*/];
152
167
  });
153
168
  }); };
@@ -64,7 +64,10 @@ var json5_1 = require("json5");
64
64
  var path_1 = require("path");
65
65
  var backports_1 = require("../../util/backports");
66
66
  var presets_1 = require("../helpers/presets");
67
- exports.run = function (args) { return __awaiter(void 0, void 0, void 0, function () {
67
+ /**
68
+ * @internal
69
+ */
70
+ exports.run = function (args /* , logger: Logger*/) { return __awaiter(void 0, void 0, void 0, function () {
68
71
  var nullLogger, file, filePath, footNotes, name, isPackage, actualConfig, migratedConfig, presetName, preset, jsTransformers, jsWithTs, jsWithBabel, presetValue, migratedValue, presetValue, migratedValue, before, after, stringify, prefix;
69
72
  return __generator(this, function (_a) {
70
73
  nullLogger = bs_logger_1.createLogger({ targets: [] });
@@ -86,9 +89,11 @@ exports.run = function (args) { return __awaiter(void 0, void 0, void 0, functio
86
89
  if (!actualConfig)
87
90
  actualConfig = {};
88
91
  migratedConfig = backports_1.backportJestConfig(nullLogger, actualConfig);
92
+ // then we check if we can use `preset`
89
93
  if (!migratedConfig.preset && args.jestPreset) {
94
+ // find the best preset
90
95
  if (args.js) {
91
- presetName = args.js === 'babel' ? "ts-jest/presets/js-with-babel" : "ts-jest/presets/js-with-ts";
96
+ presetName = args.js === 'babel' ? "ts-jest/presets/js-with-babel" /* jsWIthBabel */ : "ts-jest/presets/js-with-ts" /* jsWithTs */;
92
97
  }
93
98
  else {
94
99
  jsTransformers = Object.keys(migratedConfig.transform || {}).reduce(function (list, pattern) {
@@ -105,16 +110,18 @@ exports.run = function (args) { return __awaiter(void 0, void 0, void 0, functio
105
110
  jsWithTs = jsTransformers.includes('ts-jest');
106
111
  jsWithBabel = jsTransformers.includes('babel-jest');
107
112
  if (jsWithBabel && !jsWithTs) {
108
- presetName = "ts-jest/presets/js-with-babel";
113
+ presetName = "ts-jest/presets/js-with-babel" /* jsWIthBabel */;
109
114
  }
110
115
  else if (jsWithTs && !jsWithBabel) {
111
- presetName = "ts-jest/presets/js-with-ts";
116
+ presetName = "ts-jest/presets/js-with-ts" /* jsWithTs */;
112
117
  }
113
118
  else {
114
- presetName = "ts-jest/presets/default";
119
+ // sounds like js files are NOT handled, or handled with a unknown transformer, so we do not need to handle it
120
+ presetName = "ts-jest/presets/default" /* default */;
115
121
  }
116
122
  }
117
- presetName = presetName || "ts-jest/presets/default";
123
+ // ensure we are using a preset
124
+ presetName = presetName || "ts-jest/presets/default" /* default */;
118
125
  preset = presets_1.allPresets[presetName];
119
126
  footNotes.push("Detected preset '" + preset.label + "' as the best matching preset for your configuration.\nVisit https://kulshekhar.github.io/ts-jest/user/config/#jest-preset for more information about presets.\n");
120
127
  }
@@ -126,8 +133,10 @@ exports.run = function (args) { return __awaiter(void 0, void 0, void 0, functio
126
133
  preset = presets_1.allPresets[migratedConfig.preset] || presets_1.defaults;
127
134
  }
128
135
  }
136
+ // enforce the correct name
129
137
  if (preset)
130
138
  migratedConfig.preset = preset.name;
139
+ // check the extensions
131
140
  if (migratedConfig.moduleFileExtensions && migratedConfig.moduleFileExtensions.length && preset) {
132
141
  presetValue = dedupSort(preset.value.moduleFileExtensions || []).join('::');
133
142
  migratedValue = dedupSort(migratedConfig.moduleFileExtensions).join('::');
@@ -135,9 +144,11 @@ exports.run = function (args) { return __awaiter(void 0, void 0, void 0, functio
135
144
  delete migratedConfig.moduleFileExtensions;
136
145
  }
137
146
  }
147
+ // there is a testRegex, remove our testMatch
138
148
  if (migratedConfig.testRegex && preset) {
139
149
  migratedConfig.testMatch = null;
140
150
  }
151
+ // check the testMatch
141
152
  else if (migratedConfig.testMatch && migratedConfig.testMatch.length && preset) {
142
153
  presetValue = dedupSort(preset.value.testMatch || []).join('::');
143
154
  migratedValue = dedupSort(migratedConfig.testMatch).join('::');
@@ -145,6 +156,7 @@ exports.run = function (args) { return __awaiter(void 0, void 0, void 0, functio
145
156
  delete migratedConfig.testMatch;
146
157
  }
147
158
  }
159
+ // migrate the transform
148
160
  if (migratedConfig.transform) {
149
161
  Object.keys(migratedConfig.transform).forEach(function (key) {
150
162
  var val = migratedConfig.transform[key];
@@ -154,30 +166,45 @@ exports.run = function (args) { return __awaiter(void 0, void 0, void 0, functio
154
166
  }
155
167
  });
156
168
  }
169
+ // check if it's the same as the preset's one
157
170
  if (preset &&
158
171
  migratedConfig.transform &&
159
172
  stableStringify(migratedConfig.transform) === stableStringify(preset.value.transform)) {
160
173
  delete migratedConfig.transform;
161
174
  }
175
+ // cleanup
162
176
  cleanupConfig(actualConfig);
163
177
  cleanupConfig(migratedConfig);
164
178
  before = stableStringify(actualConfig);
165
179
  after = stableStringify(migratedConfig);
166
180
  if (after === before) {
167
181
  process.stderr.write("\nNo migration needed for given Jest configuration\n ");
168
- return [2];
182
+ return [2 /*return*/];
169
183
  }
170
184
  stringify = file.endsWith('.json') ? JSON.stringify : json5_1.stringify;
171
185
  prefix = file.endsWith('.json') ? '"jest": ' : 'module.exports = ';
186
+ // if we are using preset, inform the user that he might be able to remove some section(s)
187
+ // we couldn't check for equality
188
+ // if (usesPreset && migratedConfig.testMatch) {
189
+ // footNotes.push(`
190
+ // I couldn't check if your "testMatch" value is the same as mine which is: ${stringify(
191
+ // presets.testMatch,
192
+ // undefined,
193
+ // ' ',
194
+ // )}
195
+ // If it is the case, you can safely remove the "testMatch" from what I've migrated.
196
+ // `)
197
+ // }
172
198
  if (preset && migratedConfig.transform) {
173
199
  footNotes.push("\nI couldn't check if your \"transform\" value is the same as mine which is: " + stringify(preset.value.transform, undefined, ' ') + "\nIf it is the case, you can safely remove the \"transform\" from what I've migrated.\n");
174
200
  }
201
+ // output new config
175
202
  process.stderr.write("\nMigrated Jest configuration:\n");
176
203
  process.stdout.write("" + prefix + stringify(migratedConfig, undefined, ' ') + "\n");
177
204
  if (footNotes.length) {
178
205
  process.stderr.write("\n" + footNotes.join('\n') + "\n");
179
206
  }
180
- return [2];
207
+ return [2 /*return*/];
181
208
  });
182
209
  }); };
183
210
  function cleanupConfig(config) {
@@ -202,7 +229,7 @@ function cleanupConfig(config) {
202
229
  if (config.testMatch.length === 0)
203
230
  delete config.testMatch;
204
231
  }
205
- if (config.preset === "ts-jest/presets/default")
232
+ if (config.preset === "ts-jest/presets/default" /* default */)
206
233
  config.preset = presets_1.defaults.name;
207
234
  }
208
235
  function dedupSort(arr) {
@@ -210,9 +237,12 @@ function dedupSort(arr) {
210
237
  .filter(function (s, i, a) { return a.findIndex(function (e) { return s.toString() === e.toString(); }) === i; })
211
238
  .sort(function (a, b) { return (a.toString() > b.toString() ? 1 : a.toString() < b.toString() ? -1 : 0); });
212
239
  }
240
+ /**
241
+ * @internal
242
+ */
213
243
  exports.help = function () { return __awaiter(void 0, void 0, void 0, function () {
214
244
  return __generator(this, function (_a) {
215
245
  process.stdout.write("\nUsage:\n ts-jest config:migrate [options] <config-file>\n\nArguments:\n <config-file> Can be a js or json Jest config file. If it is a\n package.json file, the configuration will be read from\n the \"jest\" property.\n\nOptions:\n --js ts|babel Process .js files with ts-jest if 'ts' or with\n babel-jest if 'babel'\n --no-jest-preset Disable the use of Jest presets\n");
216
- return [2];
246
+ return [2 /*return*/];
217
247
  });
218
248
  }); };
package/dist/cli/help.js CHANGED
@@ -37,10 +37,16 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.help = exports.run = void 0;
40
+ /**
41
+ * @internal
42
+ */
40
43
  exports.run = function (_) { return __awaiter(void 0, void 0, void 0, function () {
41
44
  return __generator(this, function (_a) {
42
45
  process.stdout.write("\nUsage:\n ts-jest command [options] [...args]\n\nCommands:\n config:init Creates initial Jest configuration\n config:migrate Migrates a given Jest configuration\n help [command] Show this help, or help about a command\n\nExample:\n ts-jest help config:migrate\n");
43
- return [2];
46
+ return [2 /*return*/];
44
47
  });
45
48
  }); };
49
+ /**
50
+ * @internal
51
+ */
46
52
  exports.help = exports.run;
@@ -7,15 +7,17 @@ var definePreset = function (fullName) { return ({
7
7
  return this.isDefault ? 'ts-jest' : fullName;
8
8
  },
9
9
  get label() {
10
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
10
11
  return fullName.split('/').pop();
11
12
  },
12
13
  get jsVarName() {
13
14
  return this.isDefault
14
15
  ? 'defaults'
15
- :
16
+ : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
16
17
  fullName
17
18
  .split('/')
18
19
  .pop()
20
+ // eslint-disable-next-line no-useless-escape
19
21
  .replace(/\-([a-z])/g, function (_, l) { return l.toUpperCase(); });
20
22
  },
21
23
  get value() {
@@ -26,10 +28,14 @@ var definePreset = function (fullName) { return ({
26
28
  return "const { " + this.jsVarName + ": " + varName + " } = require('ts-jest/presets')";
27
29
  },
28
30
  get isDefault() {
29
- return fullName === "ts-jest/presets/default";
31
+ return fullName === "ts-jest/presets/default" /* default */;
30
32
  },
31
33
  }); };
34
+ /** @internal */
32
35
  exports.allPresets = {};
33
- exports.defaults = (exports.allPresets["ts-jest/presets/default"] = definePreset("ts-jest/presets/default"));
34
- exports.jsWithTs = (exports.allPresets["ts-jest/presets/js-with-ts"] = definePreset("ts-jest/presets/js-with-ts"));
35
- exports.jsWIthBabel = (exports.allPresets["ts-jest/presets/js-with-babel"] = definePreset("ts-jest/presets/js-with-babel"));
36
+ /** @internal */
37
+ exports.defaults = (exports.allPresets["ts-jest/presets/default" /* default */] = definePreset("ts-jest/presets/default" /* default */));
38
+ /** @internal */
39
+ exports.jsWithTs = (exports.allPresets["ts-jest/presets/js-with-ts" /* jsWithTs */] = definePreset("ts-jest/presets/js-with-ts" /* jsWithTs */));
40
+ /** @internal */
41
+ exports.jsWIthBabel = (exports.allPresets["ts-jest/presets/js-with-babel" /* jsWIthBabel */] = definePreset("ts-jest/presets/js-with-babel" /* jsWIthBabel */));
package/dist/cli/index.js CHANGED
@@ -62,6 +62,7 @@ function cli(args) {
62
62
  },
63
63
  },
64
64
  });
65
+ // deprecated
65
66
  if (parsedArgv.allowJs != null) {
66
67
  if (parsedArgv.js)
67
68
  throw new Error("The 'allowJs' and 'js' options cannot be set together.");
@@ -75,10 +76,13 @@ function cli(args) {
75
76
  command = 'help';
76
77
  _a = require("./" + command.replace(/:/g, '/')), run = _a.run, help = _a.help;
77
78
  cmd = isHelp && command !== 'help' ? help : run;
78
- return [2, cmd(parsedArgv, logger)];
79
+ return [2 /*return*/, cmd(parsedArgv, logger)];
79
80
  });
80
81
  });
81
82
  }
83
+ /**
84
+ * @internal
85
+ */
82
86
  function processArgv() {
83
87
  return __awaiter(this, void 0, void 0, function () {
84
88
  var err_1;
@@ -86,17 +90,17 @@ function processArgv() {
86
90
  switch (_a.label) {
87
91
  case 0:
88
92
  _a.trys.push([0, 2, , 3]);
89
- return [4, cli(process.argv.slice(2))];
93
+ return [4 /*yield*/, cli(process.argv.slice(2))];
90
94
  case 1:
91
95
  _a.sent();
92
96
  process.exit(0);
93
- return [3, 3];
97
+ return [3 /*break*/, 3];
94
98
  case 2:
95
99
  err_1 = _a.sent();
96
100
  logger.fatal(err_1.message);
97
101
  process.exit(1);
98
- return [3, 3];
99
- case 3: return [2];
102
+ return [3 /*break*/, 3];
103
+ case 3: return [2 /*return*/];
100
104
  }
101
105
  });
102
106
  });
@@ -20,12 +20,22 @@ exports.createCompilerInstance = void 0;
20
20
  var language_service_1 = require("./language-service");
21
21
  var transpiler_1 = require("./transpiler");
22
22
  var json_1 = require("../util/json");
23
+ /**
24
+ * Rely on TypeScript compiled output generation which contains this prefix to point to sourcemap location.
25
+ */
23
26
  var SOURCE_MAPPING_PREFIX = 'sourceMappingURL=';
27
+ /**
28
+ * Update the output remapping the source map.
29
+ */
24
30
  function updateOutput(outputText, normalizedFileName, sourceMap) {
25
31
  var base64Map = Buffer.from(updateSourceMap(sourceMap, normalizedFileName), 'utf8').toString('base64');
26
32
  var sourceMapContent = "data:application/json;charset=utf-8;base64," + base64Map;
33
+ // sourceMappingURL= prefix is always at the end of compiledOutput, using lastIndexOf should be the safest way to substring
27
34
  return (outputText.slice(0, outputText.lastIndexOf(SOURCE_MAPPING_PREFIX) + SOURCE_MAPPING_PREFIX.length) + sourceMapContent);
28
35
  }
36
+ /**
37
+ * Update the source map contents for improved output.
38
+ */
29
39
  var updateSourceMap = function (sourceMapText, normalizedFileName) {
30
40
  var sourceMap = JSON.parse(sourceMapText);
31
41
  sourceMap.file = normalizedFileName;
@@ -33,21 +43,31 @@ var updateSourceMap = function (sourceMapText, normalizedFileName) {
33
43
  delete sourceMap.sourceRoot;
34
44
  return json_1.stringify(sourceMap);
35
45
  };
46
+ /**
47
+ * Compile files which are provided by jest via transform config and cache the result in file system if users run with
48
+ * cache mode
49
+ */
36
50
  var compileAndUpdateOutput = function (compileFn, logger) { return function (code, fileName, lineOffset) {
37
51
  logger.debug({ fileName: fileName }, 'compileAndUpdateOutput(): get compile output');
38
52
  var _a = __read(compileFn(code, fileName, lineOffset), 2), value = _a[0], sourceMap = _a[1];
39
53
  return updateOutput(value, fileName, sourceMap);
40
54
  }; };
55
+ /**
56
+ * Register TypeScript compiler instance.
57
+ *
58
+ * @internal
59
+ */
41
60
  exports.createCompilerInstance = function (configs) {
42
61
  var logger = configs.logger.child({ namespace: 'ts-compiler' });
43
62
  var compilerOptions = configs.parsedTsConfig.options, tsJest = configs.tsJest;
44
63
  var extensions = ['.ts', '.tsx'];
64
+ // Enable `allowJs` when flag is set.
45
65
  if (compilerOptions.allowJs) {
46
66
  extensions.push('.js');
47
67
  extensions.push('.jsx');
48
68
  }
49
69
  var compilerInstance = !tsJest.isolatedModules
50
- ? language_service_1.initializeLanguageServiceInstance(configs, logger)
70
+ ? language_service_1.initializeLanguageServiceInstance(configs, logger) // Use language services by default
51
71
  : transpiler_1.initializeTranspilerInstance(configs, logger);
52
72
  var compile = compileAndUpdateOutput(compilerInstance.compileFn, logger);
53
73
  return { cwd: configs.cwd, compile: compile, program: compilerInstance.program };
@@ -90,11 +90,16 @@ var json_1 = require("../util/json");
90
90
  var sha1_1 = require("../util/sha1");
91
91
  function doTypeChecking(configs, diagnosedFiles, fileName, service, logger) {
92
92
  if (configs.shouldReportDiagnostic(fileName)) {
93
+ // Get the relevant diagnostics - this is 3x faster than `getPreEmitDiagnostics`.
93
94
  var diagnostics = service.getSemanticDiagnostics(fileName).concat(service.getSyntacticDiagnostics(fileName));
94
95
  diagnosedFiles.push(fileName);
96
+ // will raise or just warn diagnostics depending on config
95
97
  configs.raiseDiagnostics(diagnostics, fileName, logger);
96
98
  }
97
99
  }
100
+ /**
101
+ * @internal
102
+ */
98
103
  exports.initializeLanguageServiceInstance = function (configs, logger) {
99
104
  var _a;
100
105
  logger.debug('initializeLanguageServiceInstance(): create typescript compiler');
@@ -115,23 +120,28 @@ exports.initializeLanguageServiceInstance = function (configs, logger) {
115
120
  };
116
121
  var tsResolvedModulesCachePath;
117
122
  if (cacheDir) {
123
+ // Make sure the cache directory exists before continuing.
118
124
  mkdirp.sync(cacheDir);
119
125
  tsResolvedModulesCachePath = path_1.join(cacheDir, sha1_1.sha1('ts-jest-resolved-modules', '\x00'));
120
126
  try {
127
+ /* istanbul ignore next (already covered with unit test) */
121
128
  var cachedTSResolvedModules = fs_1.readFileSync(tsResolvedModulesCachePath, 'utf-8');
122
129
  memoryCache.resolvedModules = new Map(json_1.parse(cachedTSResolvedModules));
123
130
  }
124
131
  catch (e) { }
125
132
  }
133
+ // Initialize memory cache for typescript compiler
126
134
  configs.parsedTsConfig.fileNames.forEach(function (fileName) {
127
135
  memoryCache.files.set(fileName, {
128
136
  version: 0,
129
137
  });
130
138
  });
131
139
  function isFileInCache(fileName) {
140
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
132
141
  return memoryCache.files.has(fileName) && memoryCache.files.get(fileName).version !== 0;
133
142
  }
134
143
  var cacheReadFile = logger.wrap(serviceHostTraceCtx, 'readFile', memoize(ts.sys.readFile));
144
+ /* istanbul ignore next */
135
145
  var moduleResolutionHost = {
136
146
  fileExists: memoize(ts.sys.fileExists),
137
147
  readFile: cacheReadFile,
@@ -159,6 +169,8 @@ exports.initializeLanguageServiceInstance = function (configs, logger) {
159
169
  });
160
170
  }
161
171
  var projectVersion = 1;
172
+ // Set the file contents into cache.
173
+ /* istanbul ignore next (cover by e2e) */
162
174
  var updateMemoryCache = function (contents, fileName) {
163
175
  logger.debug({ fileName: fileName }, 'updateMemoryCache(): update memory cache for language service');
164
176
  var shouldIncrementProjectVersion = false;
@@ -171,15 +183,22 @@ exports.initializeLanguageServiceInstance = function (configs, logger) {
171
183
  shouldIncrementProjectVersion = true;
172
184
  }
173
185
  else {
186
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
174
187
  var previousContents = memoryCache.files.get(fileName).text;
188
+ // Avoid incrementing cache when nothing has changed.
175
189
  if (previousContents !== contents) {
176
190
  memoryCache.files.set(fileName, {
177
191
  text: contents,
178
192
  version: memoryCache.files.get(fileName).version + 1,
179
193
  });
194
+ // Only bump project version when file is modified in cache, not when discovered for the first time
180
195
  if (hit)
181
196
  shouldIncrementProjectVersion = true;
182
197
  }
198
+ /**
199
+ * When a file is from node_modules or referenced to a referenced project and jest wants to transform it, we need
200
+ * to make sure that the Program is updated with this information
201
+ */
183
202
  if (!fileNames.includes(fileName)) {
184
203
  shouldIncrementProjectVersion = true;
185
204
  }
@@ -194,6 +213,11 @@ exports.initializeLanguageServiceInstance = function (configs, logger) {
194
213
  var _a;
195
214
  var normalizedFileName = path_1.normalize(fileName);
196
215
  var version = (_a = memoryCache.files.get(normalizedFileName)) === null || _a === void 0 ? void 0 : _a.version;
216
+ // We need to return `undefined` and not a string here because TypeScript will use
217
+ // `getScriptVersion` and compare against their own version - which can be `undefined`.
218
+ // If we don't return `undefined` it results in `undefined === "undefined"` and run
219
+ // `createProgram` again (which is very slow). Using a `string` assertion here to avoid
220
+ // TypeScript errors from the function signature (expects `(x: string) => string`).
197
221
  return version === undefined ? undefined : String(version);
198
222
  },
199
223
  getScriptSnapshot: function (fileName) {
@@ -201,6 +225,7 @@ exports.initializeLanguageServiceInstance = function (configs, logger) {
201
225
  var normalizedFileName = path_1.normalize(fileName);
202
226
  var hit = isFileInCache(normalizedFileName);
203
227
  logger.trace({ normalizedFileName: normalizedFileName, cacheHit: hit }, 'getScriptSnapshot():', 'cache', hit ? 'hit' : 'miss');
228
+ // Read contents from TypeScript memory cache.
204
229
  if (!hit) {
205
230
  memoryCache.files.set(normalizedFileName, {
206
231
  text: cacheReadFile(normalizedFileName),
@@ -232,33 +257,47 @@ exports.initializeLanguageServiceInstance = function (configs, logger) {
232
257
  var e_1, _a;
233
258
  var _b;
234
259
  logger.debug({ fileName: fileName }, 'compileFn(): compiling using language service');
260
+ // Must set memory cache before attempting to compile
235
261
  updateMemoryCache(code, fileName);
236
262
  var output = service.getEmitOutput(fileName);
263
+ /* istanbul ignore next */
237
264
  if (tsResolvedModulesCachePath) {
265
+ // Cache resolved modules to disk so next run can reuse it
238
266
  void (function () { return __awaiter(void 0, void 0, void 0, function () {
239
267
  return __generator(this, function (_a) {
240
268
  switch (_a.label) {
241
- case 0: return [4, fs_1.writeFile(tsResolvedModulesCachePath, json_1.stringify(__spread(memoryCache.resolvedModules)), function () { })];
269
+ case 0:
270
+ // eslint-disable-next-line @typescript-eslint/await-thenable
271
+ return [4 /*yield*/, fs_1.writeFile(tsResolvedModulesCachePath, json_1.stringify(__spread(memoryCache.resolvedModules)), function () { })];
242
272
  case 1:
273
+ // eslint-disable-next-line @typescript-eslint/await-thenable
243
274
  _a.sent();
244
- return [2];
275
+ return [2 /*return*/];
245
276
  }
246
277
  });
247
278
  }); })();
248
279
  }
280
+ /**
281
+ * There might be a chance that test files are type checked even before jest executes them, we don't need to do
282
+ * type check again
283
+ */
249
284
  if (!diagnosedFiles.includes(fileName)) {
250
285
  logger.debug({ fileName: fileName }, 'compileFn(): computing diagnostics using language service');
251
286
  doTypeChecking(configs, diagnosedFiles, fileName, service, logger);
252
287
  }
288
+ /* istanbul ignore next (already covered with unit tests) */
253
289
  if (!configs.isTestFile(fileName)) {
254
290
  try {
255
291
  for (var _c = __values(memoryCache.resolvedModules.entries()), _d = _c.next(); !_d.done; _d = _c.next()) {
256
292
  var _e = __read(_d.value, 2), testFileName = _e[0], resolvedModules = _e[1];
293
+ // Only do type checking for test files which haven't been type checked before as well as the file must exist
257
294
  if (resolvedModules.includes(fileName) &&
258
295
  !diagnosedFiles.includes(testFileName) &&
259
296
  fs_1.existsSync(testFileName)) {
260
297
  var testFileContent = (_b = memoryCache.files.get(testFileName)) === null || _b === void 0 ? void 0 : _b.text;
261
298
  if (!testFileContent) {
299
+ // Must set memory cache before attempting to get diagnostics
300
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
262
301
  updateMemoryCache(cacheReadFile(testFileName), testFileName);
263
302
  }
264
303
  logger.debug({ testFileName: testFileName }, 'compileFn(): computing diagnostics using language service for test file which uses the module');
@@ -274,11 +313,13 @@ exports.initializeLanguageServiceInstance = function (configs, logger) {
274
313
  finally { if (e_1) throw e_1.error; }
275
314
  }
276
315
  }
316
+ /* istanbul ignore next (this should never happen but is kept for security) */
277
317
  if (output.emitSkipped) {
278
318
  throw new TypeError(path_1.relative(cwd, fileName) + ": Emit skipped for language service");
279
319
  }
320
+ // Throw an error when requiring `.d.ts` files.
280
321
  if (!output.outputFiles.length) {
281
- throw new TypeError(messages_1.interpolate("Unable to require `.d.ts` file for file: {{file}}.\nThis is usually the result of a faulty configuration or import. Make sure there is a `.js`, `.json` or another executable extension available alongside `{{file}}`.", {
322
+ throw new TypeError(messages_1.interpolate("Unable to require `.d.ts` file for file: {{file}}.\nThis is usually the result of a faulty configuration or import. Make sure there is a `.js`, `.json` or another executable extension available alongside `{{file}}`." /* UnableToRequireDefinitionFile */, {
282
323
  file: path_1.basename(fileName),
283
324
  }));
284
325
  }
@@ -1,6 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.initializeTranspilerInstance = void 0;
4
+ /**
5
+ * @internal
6
+ */
4
7
  exports.initializeTranspilerInstance = function (configs, logger) {
5
8
  logger.debug('initializeTranspilerInstance(): create typescript compiler');
6
9
  var _a = configs.parsedTsConfig, options = _a.options, fileNames = _a.fileNames;
@@ -18,6 +21,7 @@ exports.initializeTranspilerInstance = function (configs, logger) {
18
21
  if (result.diagnostics && configs.shouldReportDiagnostic(fileName)) {
19
22
  configs.raiseDiagnostics(result.diagnostics, fileName, logger);
20
23
  }
24
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
21
25
  return [result.outputText, result.sourceMapText];
22
26
  },
23
27
  program: program,
@@ -1,11 +1,30 @@
1
+ /**
2
+ * This is the core of settings and so ts-jest.
3
+ * Since configuration are used to create a good cache key, everything
4
+ * depending on it is here. Fast jest relies on correct cache keys
5
+ * depending on all settings that could affect the generated output.
6
+ *
7
+ * The big issue is that jest calls first `getCacheKey()` with stringified
8
+ * version of the `jest.ProjectConfig`, and then later it calls `process()`
9
+ * with the complete, object version of it.
10
+ */
1
11
  import type { Config } from '@jest/types';
2
12
  import { Logger } from 'bs-logger';
3
13
  import type { TsCompiler, TsJestGlobalOptions, TTypeScript } from '../types';
4
14
  export declare class ConfigSet {
5
15
  readonly parentOptions?: TsJestGlobalOptions | undefined;
16
+ /**
17
+ * Use by e2e, don't mark as internal
18
+ */
6
19
  get versions(): Record<string, string>;
20
+ /**
21
+ * This API can be used by custom transformers
22
+ */
7
23
  get compilerModule(): TTypeScript;
8
24
  get tsCompiler(): TsCompiler;
25
+ /**
26
+ * Use by e2e, don't mark as internal
27
+ */
9
28
  get tsJestDigest(): string;
10
29
  readonly logger: Logger;
11
30
  constructor(jestConfig: Config.ProjectConfig, parentOptions?: TsJestGlobalOptions | undefined, parentLogger?: Logger);