From 53d5ea91049e2f8d8223a641081ff4a6a6770bab Mon Sep 17 00:00:00 2001 From: Globegitter Date: Sun, 16 Sep 2018 14:58:11 +0200 Subject: [PATCH 1/7] Start adding --preserve-symlinks mode and flag. --- packages/jest-cli/src/cli/args.js | 7 +++++++ packages/jest-haste-map/src/crawlers/node.js | 4 ++++ packages/jest-resolve/src/default_resolver.js | 4 +++- packages/jest-runtime/src/script_transformer.js | 3 ++- types/Argv.js | 1 + 5 files changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/jest-cli/src/cli/args.js b/packages/jest-cli/src/cli/args.js index 4b8b970bc578..16e33fb2af32 100644 --- a/packages/jest-cli/src/cli/args.js +++ b/packages/jest-cli/src/cli/args.js @@ -420,6 +420,13 @@ export const options = { 'Will not fail if no tests are found (for example while using `--testPathPattern`.)', type: 'boolean', }, + preserveSymlinks: { + default: false, + description: + 'Find symlinked files and do not expand their file paths during' + + 'module resolution', + type: 'boolean', + }, preset: { description: "A preset that is used as a base for Jest's configuration.", type: 'string', diff --git a/packages/jest-haste-map/src/crawlers/node.js b/packages/jest-haste-map/src/crawlers/node.js index 16e1e89114b7..7fbf046e7b1a 100644 --- a/packages/jest-haste-map/src/crawlers/node.js +++ b/packages/jest-haste-map/src/crawlers/node.js @@ -16,6 +16,7 @@ import {spawn} from 'child_process'; import H from '../constants'; type Callback = (result: Array<[/* id */ string, /* mtime */ number]>) => void; +const preserveSymlinks = true; function find( roots: Array, @@ -80,6 +81,9 @@ function findNative( callback: Callback, ): void { const args = [].concat(roots); + if (preserveSymlinks) { + args.unshift('-L'); + } args.push('-type', 'f'); if (extensions.length) { args.push('('); diff --git a/packages/jest-resolve/src/default_resolver.js b/packages/jest-resolve/src/default_resolver.js index ae85c4e888d8..4e2d8359c123 100644 --- a/packages/jest-resolve/src/default_resolver.js +++ b/packages/jest-resolve/src/default_resolver.js @@ -25,6 +25,8 @@ type ResolverOptions = {| rootDir: ?Path, |}; +const preserveSymlinks = true; + export default function defaultResolver( path: Path, options: ResolverOptions, @@ -88,7 +90,7 @@ function resolveSync(target: Path, options: ResolverOptions): Path { if (isDirectory(dir)) { result = resolveAsFile(name) || resolveAsDirectory(name); } - if (result) { + if (result && !preserveSymlinks) { // Dereference symlinks to ensure we don't create a separate // module instance depending on how it was referenced. result = fs.realpathSync(result); diff --git a/packages/jest-runtime/src/script_transformer.js b/packages/jest-runtime/src/script_transformer.js index a1debe6bed15..ea2f3d01461a 100644 --- a/packages/jest-runtime/src/script_transformer.js +++ b/packages/jest-runtime/src/script_transformer.js @@ -44,6 +44,7 @@ const cache: Map = new Map(); const configToJsonMap = new Map(); // Cache regular expressions to test whether the file needs to be preprocessed const ignoreCache: WeakMap = new WeakMap(); +const preserveSymlinks = true; // To reset the cache for specific changesets (rather than package version). const CACHE_VERSION = '1'; @@ -180,7 +181,7 @@ export default class ScriptTransformer { } transformSource(filepath: Path, content: string, instrument: boolean) { - const filename = this._getRealPath(filepath); + const filename = preserveSymlinks ? filepath : this._getRealPath(filepath); const transform = this._getTransformer(filename); const cacheFilePath = this._getFileCachePath(filename, content, instrument); let sourceMapPath = cacheFilePath + '.map'; diff --git a/types/Argv.js b/types/Argv.js index ef157f155dfd..817ba16fc050 100644 --- a/types/Argv.js +++ b/types/Argv.js @@ -60,6 +60,7 @@ export type Argv = {| notifyMode: string, onlyChanged: boolean, outputFile: string, + preserveSymlinks: boolean, preset: ?string, projects: Array, replname: ?string, From aa22e769ab9bd85c0a0ed85a0dc492a3f0dd6976 Mon Sep 17 00:00:00 2001 From: Globegitter Date: Sun, 16 Sep 2018 15:04:48 +0200 Subject: [PATCH 2/7] preserve symlink in node_modules_paths. --- packages/jest-resolve/src/node_modules_paths.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/jest-resolve/src/node_modules_paths.js b/packages/jest-resolve/src/node_modules_paths.js index 84cb68a2c3fb..08dbbfcde18b 100644 --- a/packages/jest-resolve/src/node_modules_paths.js +++ b/packages/jest-resolve/src/node_modules_paths.js @@ -9,15 +9,17 @@ * @flow */ -import type {Path} from 'types/Config'; +import type { Path } from 'types/Config'; import path from 'path'; -import {sync as realpath} from 'realpath-native'; +import { sync as realpath } from 'realpath-native'; type NodeModulesPathsOptions = {| - moduleDirectory?: Array, - paths?: ?Array, + moduleDirectory?: Array < string >, + paths ?: ? Array < Path >, |}; +const preserveSymlinks = true; + export default function nodeModulesPaths( basedir: Path, options: NodeModulesPathsOptions, @@ -42,7 +44,11 @@ export default function nodeModulesPaths( // traverses parents of the physical path, not the symlinked path let physicalBasedir; try { - physicalBasedir = realpath(basedirAbs); + if (!preserveSymlinks) { + physicalBasedir = realpath(basedirAbs); + } else { + physicalBasedir = basedirAbs; + } } catch (err) { // realpath can throw, e.g. on mapped drives physicalBasedir = basedirAbs; From d05fa1019de08ff2f3dbcdf31ac2b9cb6d4230af Mon Sep 17 00:00:00 2001 From: globegitter Date: Fri, 9 Nov 2018 08:53:29 +0100 Subject: [PATCH 3/7] Smaller fixes and added todo. --- packages/jest-haste-map/src/index.js | 1 + packages/jest-resolve/src/nodeModulesPaths.js | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/jest-haste-map/src/index.js b/packages/jest-haste-map/src/index.js index d31d8f2188ff..c552621860d1 100644 --- a/packages/jest-haste-map/src/index.js +++ b/packages/jest-haste-map/src/index.js @@ -251,6 +251,7 @@ class HasteMap extends EventEmitter { rootDir: options.rootDir, roots: Array.from(new Set(options.roots)), throwOnModuleCollision: !!options.throwOnModuleCollision, + // TODO(Markus): add preserveSymlink check here useWatchman: options.useWatchman == null ? true : options.useWatchman, watch: !!options.watch, }; diff --git a/packages/jest-resolve/src/nodeModulesPaths.js b/packages/jest-resolve/src/nodeModulesPaths.js index 08dbbfcde18b..f38a7a8194c4 100644 --- a/packages/jest-resolve/src/nodeModulesPaths.js +++ b/packages/jest-resolve/src/nodeModulesPaths.js @@ -9,13 +9,13 @@ * @flow */ -import type { Path } from 'types/Config'; +import type {Path} from 'types/Config'; import path from 'path'; -import { sync as realpath } from 'realpath-native'; +import {sync as realpath} from 'realpath-native'; type NodeModulesPathsOptions = {| - moduleDirectory?: Array < string >, - paths ?: ? Array < Path >, + moduleDirectory?: Array , + paths ?: ? Array , |}; const preserveSymlinks = true; From d0b2f076a7e6d4240872eb791285472347500a10 Mon Sep 17 00:00:00 2001 From: globegitter Date: Fri, 9 Nov 2018 09:13:19 +0100 Subject: [PATCH 4/7] Progress on preserver symlinks flag. --- packages/jest-config/src/index.js | 1 + packages/jest-config/src/normalize.js | 1 + packages/jest-haste-map/src/index.js | 11 +++++++++-- packages/jest-haste-map/src/types.js | 1 + 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/jest-config/src/index.js b/packages/jest-config/src/index.js index b1832b94af6a..63fbf90c2e3f 100644 --- a/packages/jest-config/src/index.js +++ b/packages/jest-config/src/index.js @@ -134,6 +134,7 @@ const groupOptions = ( outputFile: options.outputFile, passWithNoTests: options.passWithNoTests, projects: options.projects, + preserveSymlinks: options.preserveSymlinks, replname: options.replname, reporters: options.reporters, rootDir: options.rootDir, diff --git a/packages/jest-config/src/normalize.js b/packages/jest-config/src/normalize.js index ef6886ce2a3b..af74696cc148 100644 --- a/packages/jest-config/src/normalize.js +++ b/packages/jest-config/src/normalize.js @@ -648,6 +648,7 @@ export default function normalize(options: InitialOptions, argv: Argv) { case 'onlyChanged': case 'outputFile': case 'passWithNoTests': + case 'preserveSymlinks': case 'replname': case 'reporters': case 'resetMocks': diff --git a/packages/jest-haste-map/src/index.js b/packages/jest-haste-map/src/index.js index c552621860d1..19d833542b34 100644 --- a/packages/jest-haste-map/src/index.js +++ b/packages/jest-haste-map/src/index.js @@ -62,6 +62,7 @@ type Options = { mocksPattern?: string, name: string, platforms: Array, + preserveSymlinks: boolean, providesModuleNodeModules?: Array, resetCache?: boolean, retainAllFiles: boolean, @@ -86,6 +87,7 @@ type InternalOptions = { mocksPattern: ?RegExp, name: string, platforms: Array, + preserveSymlinks: boolean, resetCache: ?boolean, retainAllFiles: boolean, rootDir: string, @@ -246,13 +248,16 @@ class HasteMap extends EventEmitter { : null, name: options.name, platforms: options.platforms, + preserveSymlinks: options.preserveSymlinks, resetCache: options.resetCache, retainAllFiles: options.retainAllFiles, rootDir: options.rootDir, roots: Array.from(new Set(options.roots)), throwOnModuleCollision: !!options.throwOnModuleCollision, - // TODO(Markus): add preserveSymlink check here - useWatchman: options.useWatchman == null ? true : options.useWatchman, + // Watchman can not handle symlinks: https://github.com/facebook/watchman/issues/105 + useWatchman: options.preserveSymlinks == true + ? false + : options.useWatchman == null ? true : options.useWatchman, watch: !!options.watch, }; this._console = options.console || global.console; @@ -684,6 +689,7 @@ class HasteMap extends EventEmitter { forceNodeFilesystemAPI: options.forceNodeFilesystemAPI, ignore, mapper: options.mapper, + preserveSymlinks: options.preserveSymlinks, rootDir: options.rootDir, roots: options.roots, }).catch(e => { @@ -705,6 +711,7 @@ class HasteMap extends EventEmitter { extensions: options.extensions, forceNodeFilesystemAPI: options.forceNodeFilesystemAPI, ignore, + preserveSymlinks: options.preserveSymlinks, rootDir: options.rootDir, roots: options.roots, }).catch(retry); diff --git a/packages/jest-haste-map/src/types.js b/packages/jest-haste-map/src/types.js index 8ee12a279fb5..1e6af41825ad 100644 --- a/packages/jest-haste-map/src/types.js +++ b/packages/jest-haste-map/src/types.js @@ -35,6 +35,7 @@ export type CrawlerOptions = {| forceNodeFilesystemAPI: boolean, ignore: IgnoreMatcher, mapper?: ?Mapper, + preserveSymlinks: boolean, rootDir: string, roots: Array, |}; From ebb09da4ae2372fa1f559b752e62687a4710c5be Mon Sep 17 00:00:00 2001 From: globegitter Date: Fri, 9 Nov 2018 09:25:38 +0100 Subject: [PATCH 5/7] Progress on piping through preserve symlinks flag. --- packages/jest-haste-map/src/crawlers/node.js | 5 +++-- packages/jest-haste-map/src/index.js | 4 ++-- packages/jest-resolve/src/defaultResolver.js | 16 ++++++++-------- packages/jest-resolve/src/index.js | 5 +++++ 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/packages/jest-haste-map/src/crawlers/node.js b/packages/jest-haste-map/src/crawlers/node.js index 07c80a433f06..c53506cb3cd0 100644 --- a/packages/jest-haste-map/src/crawlers/node.js +++ b/packages/jest-haste-map/src/crawlers/node.js @@ -17,7 +17,6 @@ import H from '../constants'; import * as fastPath from '../lib/fast_path'; type Callback = (result: Array<[/* id */ string, /* mtime */ number]>) => void; -const preserveSymlinks = true; function find( roots: Array, @@ -79,6 +78,7 @@ function findNative( roots: Array, extensions: Array, ignore: IgnoreMatcher, + preserveSymlinks: boolean, callback: Callback, ): void { const args = [].concat(roots); @@ -141,6 +141,7 @@ module.exports = function nodeCrawl( extensions, forceNodeFilesystemAPI, ignore, + preserveSymlinks, rootDir, roots, } = options; @@ -167,7 +168,7 @@ module.exports = function nodeCrawl( if (forceNodeFilesystemAPI || process.platform === 'win32') { find(roots, extensions, ignore, callback); } else { - findNative(roots, extensions, ignore, callback); + findNative(roots, extensions, ignore, preserveSymlinks, callback); } }); }; diff --git a/packages/jest-haste-map/src/index.js b/packages/jest-haste-map/src/index.js index 19d833542b34..c05f0ca0a301 100644 --- a/packages/jest-haste-map/src/index.js +++ b/packages/jest-haste-map/src/index.js @@ -255,8 +255,8 @@ class HasteMap extends EventEmitter { roots: Array.from(new Set(options.roots)), throwOnModuleCollision: !!options.throwOnModuleCollision, // Watchman can not handle symlinks: https://github.com/facebook/watchman/issues/105 - useWatchman: options.preserveSymlinks == true - ? false + useWatchman: options.preserveSymlinks == true + ? false : options.useWatchman == null ? true : options.useWatchman, watch: !!options.watch, }; diff --git a/packages/jest-resolve/src/defaultResolver.js b/packages/jest-resolve/src/defaultResolver.js index 9511788a0e37..fa625145c852 100644 --- a/packages/jest-resolve/src/defaultResolver.js +++ b/packages/jest-resolve/src/defaultResolver.js @@ -22,11 +22,10 @@ type ResolverOptions = {| extensions?: Array, moduleDirectory?: Array, paths?: ?Array, + preserveSymlinks: boolean, rootDir: ?Path, |}; -const preserveSymlinks = true; - export default function defaultResolver( path: Path, options: ResolverOptions, @@ -38,6 +37,7 @@ export default function defaultResolver( extensions: options.extensions, moduleDirectory: options.moduleDirectory, paths: options.paths, + preserveSymlinks: options.preserveSymlinks, rootDir: options.rootDir, }); } @@ -52,7 +52,7 @@ function resolveSync(target: Path, options: ResolverOptions): Path { if (REGEX_RELATIVE_IMPORT.test(target)) { // resolve relative import const resolveTarget = path.resolve(basedir, target); - const result = tryResolve(resolveTarget); + const result = tryResolve(resolveTarget, options.preserveSymlinks); if (result) { return result; } @@ -64,7 +64,7 @@ function resolveSync(target: Path, options: ResolverOptions): Path { }); for (let i = 0; i < dirs.length; i++) { const resolveTarget = path.join(dirs[i], target); - const result = tryResolve(resolveTarget); + const result = tryResolve(resolveTarget, options.preserveSymlinks); if (result) { return result; } @@ -84,11 +84,11 @@ function resolveSync(target: Path, options: ResolverOptions): Path { /* * contextual helper functions */ - function tryResolve(name: Path): ?Path { + function tryResolve(name: Path, preserveSymlinks: boolean): ?Path { const dir = path.dirname(name); let result; if (isDirectory(dir)) { - result = resolveAsFile(name) || resolveAsDirectory(name); + result = resolveAsFile(name) || resolveAsDirectory(name, preserveSymlinks); } if (result && !preserveSymlinks) { // Dereference symlinks to ensure we don't create a separate @@ -113,7 +113,7 @@ function resolveSync(target: Path, options: ResolverOptions): Path { return undefined; } - function resolveAsDirectory(name: Path): ?Path { + function resolveAsDirectory(name: Path, preserveSymlinks: boolean): ?Path { if (!isDirectory(name)) { return undefined; } @@ -127,7 +127,7 @@ function resolveSync(target: Path, options: ResolverOptions): Path { if (pkgmain && !isCurrentDirectory(pkgmain)) { const resolveTarget = path.resolve(name, pkgmain); - const result = tryResolve(resolveTarget); + const result = tryResolve(resolveTarget, preserveSymlinks); if (result) { return result; } diff --git a/packages/jest-resolve/src/index.js b/packages/jest-resolve/src/index.js index cf3ba0d85093..53acf10ad573 100644 --- a/packages/jest-resolve/src/index.js +++ b/packages/jest-resolve/src/index.js @@ -28,6 +28,7 @@ type ResolverConfig = {| moduleNameMapper: ?Array, modulePaths: Array, platforms?: Array, + preserveSymlinks?: boolean, resolver: ?Path, rootDir: ?Path, |}; @@ -38,6 +39,7 @@ type FindNodeModuleConfig = {| extensions?: Array, moduleDirectory?: Array, paths?: Array, + preserveSymlinks?: boolean, resolver?: ?Path, rootDir?: ?Path, |}; @@ -80,6 +82,7 @@ class Resolver { moduleNameMapper: options.moduleNameMapper, modulePaths: options.modulePaths, platforms: options.platforms, + preserveSymlinks: options.preserveSymlinks, resolver: options.resolver, rootDir: options.rootDir, }; @@ -106,6 +109,7 @@ class Resolver { extensions: options.extensions, moduleDirectory: options.moduleDirectory, paths: paths ? (nodePaths || []).concat(paths) : nodePaths, + preserveSymlinks: options.preserveSymlinks, rootDir: options.rootDir, }); } catch (e) {} @@ -161,6 +165,7 @@ class Resolver { extensions, moduleDirectory, paths, + preserveSymlinks: this._options.preserveSymlinks, resolver: this._options.resolver, rootDir: this._options.rootDir, }); From d0fad420b2a8d9695ee24102ec94f57e9139e76e Mon Sep 17 00:00:00 2001 From: globegitter Date: Fri, 9 Nov 2018 09:40:44 +0100 Subject: [PATCH 6/7] Progress on piping through preserve symlinks flag. --- packages/jest-config/src/index.js | 2 +- packages/jest-resolve/src/index.js | 1 + packages/jest-runtime/src/index.js | 1 + types/Config.js | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/jest-config/src/index.js b/packages/jest-config/src/index.js index 63fbf90c2e3f..22ddb8a4e35a 100644 --- a/packages/jest-config/src/index.js +++ b/packages/jest-config/src/index.js @@ -134,7 +134,6 @@ const groupOptions = ( outputFile: options.outputFile, passWithNoTests: options.passWithNoTests, projects: options.projects, - preserveSymlinks: options.preserveSymlinks, replname: options.replname, reporters: options.reporters, rootDir: options.rootDir, @@ -177,6 +176,7 @@ const groupOptions = ( modulePathIgnorePatterns: options.modulePathIgnorePatterns, modulePaths: options.modulePaths, name: options.name, + preserveSymlinks: options.preserveSymlinks, prettierPath: options.prettierPath, resetMocks: options.resetMocks, resetModules: options.resetModules, diff --git a/packages/jest-resolve/src/index.js b/packages/jest-resolve/src/index.js index 53acf10ad573..53f374a8419f 100644 --- a/packages/jest-resolve/src/index.js +++ b/packages/jest-resolve/src/index.js @@ -385,6 +385,7 @@ class Resolver { extensions, moduleDirectory, paths, + preserveSymlinks: this._options.preserveSymlinks, resolver, rootDir: this._options.rootDir, }); diff --git a/packages/jest-runtime/src/index.js b/packages/jest-runtime/src/index.js index f91e481a2925..3d25dd9c9622 100644 --- a/packages/jest-runtime/src/index.js +++ b/packages/jest-runtime/src/index.js @@ -266,6 +266,7 @@ class Runtime { moduleNameMapper: getModuleNameMapper(config), modulePaths: config.modulePaths, platforms: config.haste.platforms, + preserveSymlinks: config.preserveSymlinks, resolver: config.resolver, rootDir: config.rootDir, }); diff --git a/types/Config.js b/types/Config.js index 39eac782b764..78ef6cdcd8a0 100644 --- a/types/Config.js +++ b/types/Config.js @@ -268,6 +268,7 @@ export type ProjectConfig = {| modulePathIgnorePatterns: Array, modulePaths: Array, name: string, + preserveSymlinks: boolean, prettierPath: string, resetMocks: boolean, resetModules: boolean, From 951c9a65bf8c9a89c69cd63b1c507e4bf1c2020d Mon Sep 17 00:00:00 2001 From: globegitter Date: Wed, 14 Nov 2018 09:07:52 +0100 Subject: [PATCH 7/7] More progress on preserveSymlinks. --- packages/jest-resolve/src/nodeModulesPaths.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/jest-resolve/src/nodeModulesPaths.js b/packages/jest-resolve/src/nodeModulesPaths.js index f38a7a8194c4..3040e964c021 100644 --- a/packages/jest-resolve/src/nodeModulesPaths.js +++ b/packages/jest-resolve/src/nodeModulesPaths.js @@ -14,12 +14,11 @@ import path from 'path'; import {sync as realpath} from 'realpath-native'; type NodeModulesPathsOptions = {| - moduleDirectory?: Array , - paths ?: ? Array , + moduleDirectory?: Array, + paths?: ?Array, + preserveSymlinks?: boolean, |}; -const preserveSymlinks = true; - export default function nodeModulesPaths( basedir: Path, options: NodeModulesPathsOptions, @@ -44,7 +43,7 @@ export default function nodeModulesPaths( // traverses parents of the physical path, not the symlinked path let physicalBasedir; try { - if (!preserveSymlinks) { + if (!options.preserveSymlinks) { physicalBasedir = realpath(basedirAbs); } else { physicalBasedir = basedirAbs;