From 92b06d96b515acf9864b57e186c31fdca909bc59 Mon Sep 17 00:00:00 2001
From: Erik Ritter <erik.t.ritter@gmail.com>
Date: Sat, 20 Apr 2019 19:41:48 -0700
Subject: [PATCH] Replace colons in transform cache filenames

---
 CHANGELOG.md                                  |  1 +
 .../jest-transform/src/ScriptTransformer.ts   |  8 ++---
 .../src/__tests__/script_transformer.test.js  | 29 +++++++++++++++++++
 3 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index ad6df5adf66c..2682be8d5b53 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,7 @@
 - `[jest-core]` Make `detectOpenHandles` imply `runInBand` ([#8283](https://github.com/facebook/jest/pull/8283))
 - `[jest-haste-map]` Fix the `mapper` option which was incorrectly ignored ([#8299](https://github.com/facebook/jest/pull/8299))
 - `[jest-jasmine2]` Fix describe return value warning being shown if the describe function throws ([#8335](https://github.com/facebook/jest/pull/8335))
+- `[jest-transform]` Replace colons in transform cache filenames to support Windows
 
 ### Chore & Maintenance
 
diff --git a/packages/jest-transform/src/ScriptTransformer.ts b/packages/jest-transform/src/ScriptTransformer.ts
index 3e0e7c4d8b93..dee421aab0b7 100644
--- a/packages/jest-transform/src/ScriptTransformer.ts
+++ b/packages/jest-transform/src/ScriptTransformer.ts
@@ -121,11 +121,11 @@ export default class ScriptTransformer {
     // Create sub folders based on the cacheKey to avoid creating one
     // directory with many files.
     const cacheDir = path.join(baseCacheDir, cacheKey[0] + cacheKey[1]);
+    const cacheFilenamePrefix = path
+      .basename(filename, path.extname(filename))
+      .replace(/:/g, '_COLON_');
     const cachePath = slash(
-      path.join(
-        cacheDir,
-        path.basename(filename, path.extname(filename)) + '_' + cacheKey,
-      ),
+      path.join(cacheDir, cacheFilenamePrefix + '_' + cacheKey),
     );
     createDirectory(cacheDir);
 
diff --git a/packages/jest-transform/src/__tests__/script_transformer.test.js b/packages/jest-transform/src/__tests__/script_transformer.test.js
index 994d28d7066c..bcacc14fb8ee 100644
--- a/packages/jest-transform/src/__tests__/script_transformer.test.js
+++ b/packages/jest-transform/src/__tests__/script_transformer.test.js
@@ -152,6 +152,7 @@ describe('ScriptTransformer', () => {
 
     mockFs = object({
       '/fruits/banana.js': ['module.exports = "banana";'].join('\n'),
+      '/fruits/banana:colon.js': ['module.exports = "bananaColon";'].join('\n'),
       '/fruits/grapefruit.js': [
         'module.exports = function () { return "grapefruit"; }',
       ].join('\n'),
@@ -532,6 +533,34 @@ describe('ScriptTransformer', () => {
     expect(writeFileAtomic.sync).toBeCalled();
   });
 
+  it('reads values from the cache when the file contains colons', () => {
+    const transformConfig = {
+      ...config,
+      transform: [['^.+\\.js$', 'test_preprocessor']],
+    };
+    let scriptTransformer = new ScriptTransformer(transformConfig);
+    scriptTransformer.transform('/fruits/banana:colon.js', {});
+
+    const cachePath = getCachePath(mockFs, config);
+    expect(writeFileAtomic.sync).toBeCalled();
+    expect(writeFileAtomic.sync.mock.calls[0][0]).toBe(cachePath);
+
+    // Cache the state in `mockFsCopy`
+    const mockFsCopy = mockFs;
+    jest.resetModuleRegistry();
+    reset();
+
+    // Restore the cached fs
+    mockFs = mockFsCopy;
+    scriptTransformer = new ScriptTransformer(transformConfig);
+    scriptTransformer.transform('/fruits/banana:colon.js', {});
+
+    expect(fs.readFileSync).toHaveBeenCalledTimes(2);
+    expect(fs.readFileSync).toBeCalledWith('/fruits/banana:colon.js', 'utf8');
+    expect(fs.readFileSync).toBeCalledWith(cachePath, 'utf8');
+    expect(writeFileAtomic.sync).not.toBeCalled();
+  });
+
   it('does not reuse the in-memory cache between different projects', () => {
     const scriptTransformer = new ScriptTransformer({
       ...config,