From 27bfc927d92d622621ba867b2ac22f8db1bd9c05 Mon Sep 17 00:00:00 2001
From: Andrew Bradley <cspotcode@gmail.com>
Date: Sun, 6 Feb 2022 15:08:24 -0500
Subject: [PATCH 1/6] tweak `swc` jsdoc to link to ts-node website, since it
 requires installing additional deps

---
 src/index.ts | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/index.ts b/src/index.ts
index ee542e733..d83176eff 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -265,6 +265,8 @@ export interface CreateOptions {
    * Transpile with swc instead of the TypeScript compiler, and skip typechecking.
    *
    * Equivalent to setting both `transpileOnly: true` and `transpiler: 'ts-node/transpilers/swc'`
+   *
+   * For complete instructions: https://typestrong.org/ts-node/docs/transpilers
    */
   swc?: boolean;
   /**

From 3398558e01b15c2ce8b14a12711bf89d24d1f467 Mon Sep 17 00:00:00 2001
From: Andrew Bradley <cspotcode@gmail.com>
Date: Sun, 6 Feb 2022 19:20:28 -0500
Subject: [PATCH 2/6] WIP

---
 src/configuration.ts      | 12 +++++++---
 src/index.ts              | 47 ++++++++++++++++++++++-----------------
 src/resolver-functions.ts | 13 +++++------
 src/transpilers/swc.ts    | 10 ++++-----
 src/transpilers/types.ts  |  3 ++-
 src/util.ts               | 26 ++++++++++++++++++++++
 6 files changed, 73 insertions(+), 38 deletions(-)

diff --git a/src/configuration.ts b/src/configuration.ts
index b536926dd..e961265b1 100644
--- a/src/configuration.ts
+++ b/src/configuration.ts
@@ -10,7 +10,7 @@ import {
 import type { TSInternal } from './ts-compiler-types';
 import { createTsInternals } from './ts-internals';
 import { getDefaultTsconfigJsonForNodeVersion } from './tsconfigs';
-import { assign, createRequire } from './util';
+import { assign, createProjectLocalResolveHelper } from './util';
 
 /**
  * TypeScript compiler option values required by `ts-node` which cannot be overridden.
@@ -172,9 +172,9 @@ export function readConfig(
     // Some options are relative to the config file, so must be converted to absolute paths here
     if (options.require) {
       // Modules are found relative to the tsconfig file, not the `dir` option
-      const tsconfigRelativeRequire = createRequire(configPath);
+      const tsconfigRelativeResolver = createProjectLocalResolveHelper(configPath);
       options.require = options.require.map((path: string) =>
-        tsconfigRelativeRequire.resolve(path)
+        tsconfigRelativeResolver(path, false)
       );
     }
     if (options.scopeDir) {
@@ -185,6 +185,12 @@ export function readConfig(
     if (options.moduleTypes) {
       optionBasePaths.moduleTypes = basePath;
     }
+    if (options.transpiler != null) {
+      optionBasePaths.transpiler = basePath;
+    }
+    if (options.compiler != null) {
+      optionBasePaths.compiler = basePath;
+    }
 
     assign(tsNodeOptionsFromTsconfig, options);
   }
diff --git a/src/index.ts b/src/index.ts
index d83176eff..738ad19db 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -12,8 +12,11 @@ import {
   assign,
   attemptRequireWithV8CompileCache,
   cachedLookup,
+  createProjectLocalResolveHelper,
+  getBasePathForProjectLocalDependencyResolution,
   normalizeSlashes,
   parse,
+  ProjectLocalResolveHelper,
   split,
   yn,
 } from './util';
@@ -373,6 +376,8 @@ type ModuleTypes = Record<string, 'cjs' | 'esm' | 'package'>;
 /** @internal */
 export interface OptionBasePaths {
   moduleTypes?: string;
+  transpiler?: string;
+  compiler?: string;
 }
 
 /**
@@ -501,6 +506,8 @@ export interface Service {
   enableExperimentalEsmLoaderInterop(): void;
   /** @internal */
   transpileOnly: boolean;
+  /** @internal */
+  projectLocalResolveHelper: ProjectLocalResolveHelper;
 }
 
 /**
@@ -589,17 +596,16 @@ export function create(rawOptions: CreateOptions = {}): Service {
    * be changed by the tsconfig, so we have to do this twice.
    */
   function loadCompiler(name: string | undefined, relativeToPath: string) {
-    const compiler = require.resolve(name || 'typescript', {
-      paths: [relativeToPath, __dirname],
-    });
+    const projectLocalResolveHelper = createProjectLocalResolveHelper(relativeToPath);
+    const compiler = projectLocalResolveHelper(name || 'typescript', true);
     const ts: typeof _ts = attemptRequireWithV8CompileCache(require, compiler);
-    return { compiler, ts };
+    return { compiler, ts, projectLocalResolveHelper };
   }
 
   // Compute minimum options to read the config file.
-  let { compiler, ts } = loadCompiler(
+  let { compiler, ts, projectLocalResolveHelper } = loadCompiler(
     compilerName,
-    rawOptions.projectSearchDir ?? rawOptions.project ?? cwd
+    getBasePathForProjectLocalDependencyResolution(undefined, rawOptions.projectSearchDir, rawOptions.project, cwd)
   );
 
   // Read config file and merge new options between env and CLI options.
@@ -617,6 +623,14 @@ export function create(rawOptions: CreateOptions = {}): Service {
     ...(rawOptions.require || []),
   ];
 
+  // Re-load the compiler in case it has changed.
+  // Compiler is loaded relative to tsconfig.json, so tsconfig discovery may cause us to load a
+  // different compiler than we did above, even if the name has not changed.
+  if (configFilePath) {
+    ({ compiler, ts, projectLocalResolveHelper } = loadCompiler(options.compiler,
+      getBasePathForProjectLocalDependencyResolution(configFilePath, rawOptions.projectSearchDir, rawOptions.project, cwd)));
+  }
+
   // Experimental REPL await is not compatible targets lower than ES2018
   const targetSupportsTla = config.options.target! >= ts.ScriptTarget.ES2018;
   if (options.experimentalReplAwait === true && !targetSupportsTla) {
@@ -637,13 +651,6 @@ export function create(rawOptions: CreateOptions = {}): Service {
     tsVersionSupportsTla &&
     targetSupportsTla;
 
-  // Re-load the compiler in case it has changed.
-  // Compiler is loaded relative to tsconfig.json, so tsconfig discovery may cause us to load a
-  // different compiler than we did above, even if the name has not changed.
-  if (configFilePath) {
-    ({ compiler, ts } = loadCompiler(options.compiler, configFilePath));
-  }
-
   // swc implies two other options
   // typeCheck option was implemented specifically to allow overriding tsconfig transpileOnly from the command-line
   // So we should allow using typeCheck to override swc
@@ -735,14 +742,11 @@ export function create(rawOptions: CreateOptions = {}): Service {
       typeof transpiler === 'string' ? transpiler : transpiler[0];
     const transpilerOptions =
       typeof transpiler === 'string' ? {} : transpiler[1] ?? {};
-    // TODO mimic fixed resolution logic from loadCompiler main
-    // TODO refactor into a more generic "resolve dep relative to project" helper
-    const transpilerPath = require.resolve(transpilerName, {
-      paths: [cwd, __dirname],
-    });
+    // TODO mimic fixed resolution logic from loadCompiler main (I forget what this comment is talking about)
+    const transpilerPath = projectLocalResolveHelper(transpilerName, true);
     const transpilerFactory: TranspilerFactory = require(transpilerPath).create;
     customTranspiler = transpilerFactory({
-      service: { options, config },
+      service: { options, config, projectLocalResolveHelper },
       ...transpilerOptions,
     });
   }
@@ -927,7 +931,7 @@ export function create(rawOptions: CreateOptions = {}): Service {
         ts,
         cwd,
         config,
-        configFilePath,
+        projectLocalResolveHelper,
       });
       serviceHost.resolveModuleNames = resolveModuleNames;
       serviceHost.getResolvedModuleWithFailedLookupLocationsFromCache =
@@ -1078,10 +1082,10 @@ export function create(rawOptions: CreateOptions = {}): Service {
       } = createResolverFunctions({
         host,
         cwd,
-        configFilePath,
         config,
         ts,
         getCanonicalFileName,
+        projectLocalResolveHelper,
       });
       host.resolveModuleNames = resolveModuleNames;
       host.resolveTypeReferenceDirectives = resolveTypeReferenceDirectives;
@@ -1358,6 +1362,7 @@ export function create(rawOptions: CreateOptions = {}): Service {
     installSourceMapSupport,
     enableExperimentalEsmLoaderInterop,
     transpileOnly,
+    projectLocalResolveHelper,
   };
 }
 
diff --git a/src/resolver-functions.ts b/src/resolver-functions.ts
index a624e6940..b525c20fc 100644
--- a/src/resolver-functions.ts
+++ b/src/resolver-functions.ts
@@ -1,5 +1,6 @@
 import { resolve } from 'path';
 import type * as _ts from 'typescript';
+import type { ProjectLocalResolveHelper } from './util';
 
 /**
  * @internal
@@ -11,9 +12,9 @@ export function createResolverFunctions(kwargs: {
   cwd: string;
   getCanonicalFileName: (filename: string) => string;
   config: _ts.ParsedCommandLine;
-  configFilePath: string | undefined;
+  projectLocalResolveHelper: ProjectLocalResolveHelper;
 }) {
-  const { host, ts, config, cwd, getCanonicalFileName, configFilePath } =
+  const { host, ts, config, cwd, getCanonicalFileName, projectLocalResolveHelper } =
     kwargs;
   const moduleResolutionCache = ts.createModuleResolutionCache(
     cwd,
@@ -136,12 +137,8 @@ export function createResolverFunctions(kwargs: {
           // Resolve @types/node relative to project first, then __dirname (copy logic from elsewhere / refactor into reusable function)
           let typesNodePackageJsonPath: string | undefined;
           try {
-            typesNodePackageJsonPath = require.resolve(
-              '@types/node/package.json',
-              {
-                paths: [configFilePath ?? cwd, __dirname],
-              }
-            );
+            // TODO unify this require.resolve with generic fallback helper?
+            typesNodePackageJsonPath = projectLocalResolveHelper('@types/node/package.json', true);
           } catch {} // gracefully do nothing when @types/node is not installed for any reason
           if (typesNodePackageJsonPath) {
             const typeRoots = [resolve(typesNodePackageJsonPath, '../..')];
diff --git a/src/transpilers/swc.ts b/src/transpilers/swc.ts
index 3111bfc16..c0f28ef12 100644
--- a/src/transpilers/swc.ts
+++ b/src/transpilers/swc.ts
@@ -15,23 +15,23 @@ export interface SwcTranspilerOptions extends CreateTranspilerOptions {
 export function create(createOptions: SwcTranspilerOptions): Transpiler {
   const {
     swc,
-    service: { config },
+    service: { config, projectLocalResolveHelper },
   } = createOptions;
 
   // Load swc compiler
   let swcInstance: typeof swcWasm;
   if (typeof swc === 'string') {
-    swcInstance = require(swc) as typeof swcWasm;
+    swcInstance = require(projectLocalResolveHelper(swc, true)) as typeof swcWasm;
   } else if (swc == null) {
     let swcResolved;
     try {
-      swcResolved = require.resolve('@swc/core');
+      swcResolved = projectLocalResolveHelper('@swc/core', true);
     } catch (e) {
       try {
-        swcResolved = require.resolve('@swc/wasm');
+        swcResolved = projectLocalResolveHelper('@swc/wasm', true);
       } catch (e) {
         throw new Error(
-          'swc compiler requires either @swc/core or @swc/wasm to be installed as dependencies'
+          'swc compiler requires either @swc/core or @swc/wasm to be installed as a dependency.  See https://typestrong.org/ts-node/docs/transpilers'
         );
       }
     }
diff --git a/src/transpilers/types.ts b/src/transpilers/types.ts
index 3c1e7afc3..425005c38 100644
--- a/src/transpilers/types.ts
+++ b/src/transpilers/types.ts
@@ -16,7 +16,8 @@ export type TranspilerFactory = (
 ) => Transpiler;
 export interface CreateTranspilerOptions {
   // TODO this is confusing because its only a partial Service.  Rename?
-  service: Pick<Service, 'config' | 'options'>;
+  // Careful: must avoid stripInternal breakage by guarding with Extract<>
+  service: Pick<Service, Extract<'config' | 'options' | 'projectLocalResolveHelper', keyof Service>>;
 }
 export interface Transpiler {
   // TODOs
diff --git a/src/util.ts b/src/util.ts
index 217dc6669..87217667f 100644
--- a/src/util.ts
+++ b/src/util.ts
@@ -113,3 +113,29 @@ export function attemptRequireWithV8CompileCache(
     return requireFn(specifier);
   }
 }
+
+/**
+ * Helper to discover dependencies relative to a user's project, optionally
+ * falling back to relative to ts-node.  This supports global installations of
+ * ts-node, for example where someone does `#!/usr/bin/env -S ts-node --swc` and
+ * we need to fallback to a global install of @swc/core
+ * @internal
+ */
+export function createProjectLocalResolveHelper(localDirectory: string) {
+  return function projectLocalResolveHelper(specifier: string, fallbackToTsNodeRelative: boolean) {
+    return require.resolve(specifier, {
+      paths: fallbackToTsNodeRelative ? [localDirectory, __dirname] : [localDirectory]
+    });
+  }
+}
+/** @internal */
+export type ProjectLocalResolveHelper = ReturnType<typeof createProjectLocalResolveHelper>;
+
+/**
+ * Used as a reminder of all the factors we must consider when finding project-local dependencies and when a config file
+ * on disk may or may not exist.
+ * @internal
+ */
+export function getBasePathForProjectLocalDependencyResolution(configFilePath: string | undefined, projectSearchDirOption: string | undefined, projectOption: string | undefined, cwdOption: string) {
+  return configFilePath ?? projectSearchDirOption ?? projectOption ?? cwdOption;
+}

From ae7690539364b3f8d8297b351d0a8a91cea7e218 Mon Sep 17 00:00:00 2001
From: Andrew Bradley <cspotcode@gmail.com>
Date: Sun, 6 Feb 2022 19:49:35 -0500
Subject: [PATCH 3/6] WIP

---
 src/index.ts              | 1 -
 src/resolver-functions.ts | 1 -
 2 files changed, 2 deletions(-)

diff --git a/src/index.ts b/src/index.ts
index 738ad19db..45006cc97 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -742,7 +742,6 @@ export function create(rawOptions: CreateOptions = {}): Service {
       typeof transpiler === 'string' ? transpiler : transpiler[0];
     const transpilerOptions =
       typeof transpiler === 'string' ? {} : transpiler[1] ?? {};
-    // TODO mimic fixed resolution logic from loadCompiler main (I forget what this comment is talking about)
     const transpilerPath = projectLocalResolveHelper(transpilerName, true);
     const transpilerFactory: TranspilerFactory = require(transpilerPath).create;
     customTranspiler = transpilerFactory({
diff --git a/src/resolver-functions.ts b/src/resolver-functions.ts
index b525c20fc..f478646b1 100644
--- a/src/resolver-functions.ts
+++ b/src/resolver-functions.ts
@@ -137,7 +137,6 @@ export function createResolverFunctions(kwargs: {
           // Resolve @types/node relative to project first, then __dirname (copy logic from elsewhere / refactor into reusable function)
           let typesNodePackageJsonPath: string | undefined;
           try {
-            // TODO unify this require.resolve with generic fallback helper?
             typesNodePackageJsonPath = projectLocalResolveHelper('@types/node/package.json', true);
           } catch {} // gracefully do nothing when @types/node is not installed for any reason
           if (typesNodePackageJsonPath) {

From d96591e59da4cd66d30d016ac5fe6c7d50174758 Mon Sep 17 00:00:00 2001
From: Andrew Bradley <cspotcode@gmail.com>
Date: Sun, 6 Feb 2022 19:55:58 -0500
Subject: [PATCH 4/6] lint-fix

---
 src/configuration.ts      |  3 ++-
 src/index.ts              | 21 +++++++++++++++++----
 src/resolver-functions.ts | 15 ++++++++++++---
 src/transpilers/swc.ts    |  5 ++++-
 src/transpilers/types.ts  |  5 ++++-
 src/util.ts               | 22 +++++++++++++++++-----
 6 files changed, 56 insertions(+), 15 deletions(-)

diff --git a/src/configuration.ts b/src/configuration.ts
index e961265b1..5e2b9927c 100644
--- a/src/configuration.ts
+++ b/src/configuration.ts
@@ -172,7 +172,8 @@ export function readConfig(
     // Some options are relative to the config file, so must be converted to absolute paths here
     if (options.require) {
       // Modules are found relative to the tsconfig file, not the `dir` option
-      const tsconfigRelativeResolver = createProjectLocalResolveHelper(configPath);
+      const tsconfigRelativeResolver =
+        createProjectLocalResolveHelper(configPath);
       options.require = options.require.map((path: string) =>
         tsconfigRelativeResolver(path, false)
       );
diff --git a/src/index.ts b/src/index.ts
index 45006cc97..6e0104020 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -596,7 +596,8 @@ export function create(rawOptions: CreateOptions = {}): Service {
    * be changed by the tsconfig, so we have to do this twice.
    */
   function loadCompiler(name: string | undefined, relativeToPath: string) {
-    const projectLocalResolveHelper = createProjectLocalResolveHelper(relativeToPath);
+    const projectLocalResolveHelper =
+      createProjectLocalResolveHelper(relativeToPath);
     const compiler = projectLocalResolveHelper(name || 'typescript', true);
     const ts: typeof _ts = attemptRequireWithV8CompileCache(require, compiler);
     return { compiler, ts, projectLocalResolveHelper };
@@ -605,7 +606,12 @@ export function create(rawOptions: CreateOptions = {}): Service {
   // Compute minimum options to read the config file.
   let { compiler, ts, projectLocalResolveHelper } = loadCompiler(
     compilerName,
-    getBasePathForProjectLocalDependencyResolution(undefined, rawOptions.projectSearchDir, rawOptions.project, cwd)
+    getBasePathForProjectLocalDependencyResolution(
+      undefined,
+      rawOptions.projectSearchDir,
+      rawOptions.project,
+      cwd
+    )
   );
 
   // Read config file and merge new options between env and CLI options.
@@ -627,8 +633,15 @@ export function create(rawOptions: CreateOptions = {}): Service {
   // Compiler is loaded relative to tsconfig.json, so tsconfig discovery may cause us to load a
   // different compiler than we did above, even if the name has not changed.
   if (configFilePath) {
-    ({ compiler, ts, projectLocalResolveHelper } = loadCompiler(options.compiler,
-      getBasePathForProjectLocalDependencyResolution(configFilePath, rawOptions.projectSearchDir, rawOptions.project, cwd)));
+    ({ compiler, ts, projectLocalResolveHelper } = loadCompiler(
+      options.compiler,
+      getBasePathForProjectLocalDependencyResolution(
+        configFilePath,
+        rawOptions.projectSearchDir,
+        rawOptions.project,
+        cwd
+      )
+    ));
   }
 
   // Experimental REPL await is not compatible targets lower than ES2018
diff --git a/src/resolver-functions.ts b/src/resolver-functions.ts
index f478646b1..f032bf0a8 100644
--- a/src/resolver-functions.ts
+++ b/src/resolver-functions.ts
@@ -14,8 +14,14 @@ export function createResolverFunctions(kwargs: {
   config: _ts.ParsedCommandLine;
   projectLocalResolveHelper: ProjectLocalResolveHelper;
 }) {
-  const { host, ts, config, cwd, getCanonicalFileName, projectLocalResolveHelper } =
-    kwargs;
+  const {
+    host,
+    ts,
+    config,
+    cwd,
+    getCanonicalFileName,
+    projectLocalResolveHelper,
+  } = kwargs;
   const moduleResolutionCache = ts.createModuleResolutionCache(
     cwd,
     getCanonicalFileName,
@@ -137,7 +143,10 @@ export function createResolverFunctions(kwargs: {
           // Resolve @types/node relative to project first, then __dirname (copy logic from elsewhere / refactor into reusable function)
           let typesNodePackageJsonPath: string | undefined;
           try {
-            typesNodePackageJsonPath = projectLocalResolveHelper('@types/node/package.json', true);
+            typesNodePackageJsonPath = projectLocalResolveHelper(
+              '@types/node/package.json',
+              true
+            );
           } catch {} // gracefully do nothing when @types/node is not installed for any reason
           if (typesNodePackageJsonPath) {
             const typeRoots = [resolve(typesNodePackageJsonPath, '../..')];
diff --git a/src/transpilers/swc.ts b/src/transpilers/swc.ts
index c0f28ef12..fedc6a3af 100644
--- a/src/transpilers/swc.ts
+++ b/src/transpilers/swc.ts
@@ -21,7 +21,10 @@ export function create(createOptions: SwcTranspilerOptions): Transpiler {
   // Load swc compiler
   let swcInstance: typeof swcWasm;
   if (typeof swc === 'string') {
-    swcInstance = require(projectLocalResolveHelper(swc, true)) as typeof swcWasm;
+    swcInstance = require(projectLocalResolveHelper(
+      swc,
+      true
+    )) as typeof swcWasm;
   } else if (swc == null) {
     let swcResolved;
     try {
diff --git a/src/transpilers/types.ts b/src/transpilers/types.ts
index 425005c38..ab524cbdc 100644
--- a/src/transpilers/types.ts
+++ b/src/transpilers/types.ts
@@ -17,7 +17,10 @@ export type TranspilerFactory = (
 export interface CreateTranspilerOptions {
   // TODO this is confusing because its only a partial Service.  Rename?
   // Careful: must avoid stripInternal breakage by guarding with Extract<>
-  service: Pick<Service, Extract<'config' | 'options' | 'projectLocalResolveHelper', keyof Service>>;
+  service: Pick<
+    Service,
+    Extract<'config' | 'options' | 'projectLocalResolveHelper', keyof Service>
+  >;
 }
 export interface Transpiler {
   // TODOs
diff --git a/src/util.ts b/src/util.ts
index 87217667f..ca8536d8a 100644
--- a/src/util.ts
+++ b/src/util.ts
@@ -122,20 +122,32 @@ export function attemptRequireWithV8CompileCache(
  * @internal
  */
 export function createProjectLocalResolveHelper(localDirectory: string) {
-  return function projectLocalResolveHelper(specifier: string, fallbackToTsNodeRelative: boolean) {
+  return function projectLocalResolveHelper(
+    specifier: string,
+    fallbackToTsNodeRelative: boolean
+  ) {
     return require.resolve(specifier, {
-      paths: fallbackToTsNodeRelative ? [localDirectory, __dirname] : [localDirectory]
+      paths: fallbackToTsNodeRelative
+        ? [localDirectory, __dirname]
+        : [localDirectory],
     });
-  }
+  };
 }
 /** @internal */
-export type ProjectLocalResolveHelper = ReturnType<typeof createProjectLocalResolveHelper>;
+export type ProjectLocalResolveHelper = ReturnType<
+  typeof createProjectLocalResolveHelper
+>;
 
 /**
  * Used as a reminder of all the factors we must consider when finding project-local dependencies and when a config file
  * on disk may or may not exist.
  * @internal
  */
-export function getBasePathForProjectLocalDependencyResolution(configFilePath: string | undefined, projectSearchDirOption: string | undefined, projectOption: string | undefined, cwdOption: string) {
+export function getBasePathForProjectLocalDependencyResolution(
+  configFilePath: string | undefined,
+  projectSearchDirOption: string | undefined,
+  projectOption: string | undefined,
+  cwdOption: string
+) {
   return configFilePath ?? projectSearchDirOption ?? projectOption ?? cwdOption;
 }

From e5ac0e82db2cd320de5da773fd0c495228029097 Mon Sep 17 00:00:00 2001
From: Andrew Bradley <cspotcode@gmail.com>
Date: Sun, 6 Feb 2022 20:18:02 -0500
Subject: [PATCH 5/6] fix

---
 src/configuration.ts | 2 +-
 src/util.ts          | 7 ++++++-
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/src/configuration.ts b/src/configuration.ts
index 5e2b9927c..176d92ee3 100644
--- a/src/configuration.ts
+++ b/src/configuration.ts
@@ -173,7 +173,7 @@ export function readConfig(
     if (options.require) {
       // Modules are found relative to the tsconfig file, not the `dir` option
       const tsconfigRelativeResolver =
-        createProjectLocalResolveHelper(configPath);
+        createProjectLocalResolveHelper(dirname(configPath));
       options.require = options.require.map((path: string) =>
         tsconfigRelativeResolver(path, false)
       );
diff --git a/src/util.ts b/src/util.ts
index ca8536d8a..bc79d6f8e 100644
--- a/src/util.ts
+++ b/src/util.ts
@@ -4,6 +4,7 @@ import {
 } from 'module';
 import type _createRequire from 'create-require';
 import * as ynModule from 'yn';
+import { dirname } from 'path';
 
 /** @internal */
 export const createRequire =
@@ -149,5 +150,9 @@ export function getBasePathForProjectLocalDependencyResolution(
   projectOption: string | undefined,
   cwdOption: string
 ) {
-  return configFilePath ?? projectSearchDirOption ?? projectOption ?? cwdOption;
+  if(configFilePath != null) return dirname(configFilePath);
+  return projectSearchDirOption ?? projectOption ?? cwdOption;
+  // TODO technically breaks if projectOption is path to a file, not a directory,
+  // and we attempt to resolve relative specifiers.  By the time we resolve relative specifiers,
+  // should have configFilePath, so not reach this codepath.
 }

From 37b77dd9c731c4014551c2032e82785648a92b37 Mon Sep 17 00:00:00 2001
From: Andrew Bradley <cspotcode@gmail.com>
Date: Sun, 6 Feb 2022 20:23:38 -0500
Subject: [PATCH 6/6] lint-fix

---
 src/configuration.ts | 5 +++--
 src/util.ts          | 2 +-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/src/configuration.ts b/src/configuration.ts
index 176d92ee3..ff38ddd44 100644
--- a/src/configuration.ts
+++ b/src/configuration.ts
@@ -172,8 +172,9 @@ export function readConfig(
     // Some options are relative to the config file, so must be converted to absolute paths here
     if (options.require) {
       // Modules are found relative to the tsconfig file, not the `dir` option
-      const tsconfigRelativeResolver =
-        createProjectLocalResolveHelper(dirname(configPath));
+      const tsconfigRelativeResolver = createProjectLocalResolveHelper(
+        dirname(configPath)
+      );
       options.require = options.require.map((path: string) =>
         tsconfigRelativeResolver(path, false)
       );
diff --git a/src/util.ts b/src/util.ts
index bc79d6f8e..adc5eaca9 100644
--- a/src/util.ts
+++ b/src/util.ts
@@ -150,7 +150,7 @@ export function getBasePathForProjectLocalDependencyResolution(
   projectOption: string | undefined,
   cwdOption: string
 ) {
-  if(configFilePath != null) return dirname(configFilePath);
+  if (configFilePath != null) return dirname(configFilePath);
   return projectSearchDirOption ?? projectOption ?? cwdOption;
   // TODO technically breaks if projectOption is path to a file, not a directory,
   // and we attempt to resolve relative specifiers.  By the time we resolve relative specifiers,