diff --git a/src/loader/built-in/json/module.ts b/src/loader/built-in/json/module.ts index 574094c7..e119edd1 100644 --- a/src/loader/built-in/json/module.ts +++ b/src/loader/built-in/json/module.ts @@ -6,7 +6,8 @@ */ import fs from 'node:fs'; -import { buildFilePath, handleException } from '../../../utils'; +import { buildFilePath } from '../../../locator'; +import { handleException } from '../../../utils'; import type { Loader } from '../../type'; export class JSONLoader implements Loader { diff --git a/src/loader/built-in/module/module.ts b/src/loader/built-in/module/module.ts index 2f561427..56001337 100644 --- a/src/loader/built-in/module/module.ts +++ b/src/loader/built-in/module/module.ts @@ -10,9 +10,16 @@ import type { JITI } from 'jiti'; import createJITI from 'jiti'; import { pathToFileURL } from 'node:url'; import type { LocatorInfo } from '../../../locator'; -import { pathToLocatorInfo } from '../../../locator'; import { - buildFilePath, buildFilePathWithoutExtension, handleException, hasStringProperty, isObject, + buildFilePath, + buildFilePathWithoutExtension, + isLocatorInfo, + pathToLocatorInfo, +} from '../../../locator'; +import { + handleException, + hasStringProperty, isFilePath, + isObject, } from '../../../utils'; import type { Loader } from '../../type'; import type { ScriptFileLoadOptions } from './type'; @@ -65,60 +72,50 @@ export class ModuleLoader implements Loader { data: LocatorInfo | string, options?: ScriptFileLoadOptions, ) : Promise { - const locatorInfo = this.buildLocatorInfo(data); - options = options || {}; - - let filePath : string; - if (options.withExtension) { - filePath = buildFilePath(locatorInfo); - } else { - filePath = buildFilePathWithoutExtension(locatorInfo); - } - - if (options.withFilePrefix) { - filePath = pathToFileURL(filePath).href; - } + const [name, locatorInfo] = this.build(data, options); try { // segmentation fault // issue: https://github.com/nodejs/node/issues/35889 if (isJestRuntimeEnvironment()) { // eslint-disable-next-line global-require,import/no-dynamic-require - return require(filePath); + return require(name); } - return await import(filePath); + return await import(name); } catch (e) { /* istanbul ignore next */ if ( isObject(e) && hasStringProperty(e, 'code') ) { - if ( - !options.withExtension && - ( - e.code === 'ERR_MODULE_NOT_FOUND' || - e.code === 'MODULE_NOT_FOUND' - ) - ) { - return this.load(locatorInfo, { - ...options, - withExtension: true, - }); - } - - if ( - !options.withFilePrefix && - ( - e.code === 'ERR_UNSUPPORTED_ESM_URL_SCHEME' || - e.code === 'UNSUPPORTED_ESM_URL_SCHEME' - ) - ) { - return this.load(locatorInfo, { - ...options, - withFilePrefix: true, - }); + if (locatorInfo) { + if ( + !options.withExtension && + ( + e.code === 'ERR_MODULE_NOT_FOUND' || + e.code === 'MODULE_NOT_FOUND' + ) + ) { + return this.load(locatorInfo, { + ...options, + withExtension: true, + }); + } + + if ( + !options.withFilePrefix && + ( + e.code === 'ERR_UNSUPPORTED_ESM_URL_SCHEME' || + e.code === 'UNSUPPORTED_ESM_URL_SCHEME' + ) + ) { + return this.load(locatorInfo, { + ...options, + withFilePrefix: true, + }); + } } throw new BaseError({ @@ -137,37 +134,31 @@ export class ModuleLoader implements Loader { data: LocatorInfo | string, options?: ScriptFileLoadOptions, ) : unknown { - const locatorInfo = this.buildLocatorInfo(data); - options = options || {}; - - let filePath : string; - if (options.withExtension) { - filePath = buildFilePath(locatorInfo); - } else { - filePath = buildFilePathWithoutExtension(locatorInfo); - } + const [name, locatorInfo] = this.build(data, options); try { // eslint-disable-next-line global-require,import/no-dynamic-require - return require(filePath); + return require(name); } catch (e) { /* istanbul ignore next */ if ( isObject(e) && hasStringProperty(e, 'code') ) { - if ( - !options.withExtension && - ( - e.code === 'ERR_MODULE_NOT_FOUND' || - e.code === 'MODULE_NOT_FOUND' - ) - ) { - return this.loadSync(locatorInfo, { - ...options, - withExtension: true, - }); + if (locatorInfo) { + if ( + !options.withExtension && + ( + e.code === 'ERR_MODULE_NOT_FOUND' || + e.code === 'MODULE_NOT_FOUND' + ) + ) { + return this.loadSync(locatorInfo, { + ...options, + withExtension: true, + }); + } } throw new BaseError({ @@ -181,11 +172,35 @@ export class ModuleLoader implements Loader { } } - private buildLocatorInfo(input: LocatorInfo | string) : LocatorInfo { - if (typeof input === 'string') { - return pathToLocatorInfo(input); + private build( + data: LocatorInfo | string, + options: ScriptFileLoadOptions, + ) : [string, LocatorInfo | undefined] { + let name : string; + let locatorInfo : LocatorInfo | undefined; + + options = options || {}; + + if (isLocatorInfo(data) || isFilePath(data)) { + if (typeof data === 'string') { + locatorInfo = pathToLocatorInfo(data); + } else { + locatorInfo = data; + } + + if (options.withExtension) { + name = buildFilePath(locatorInfo); + } else { + name = buildFilePathWithoutExtension(locatorInfo); + } + + if (options.withFilePrefix) { + name = pathToFileURL(name).href; + } + } else { + name = data; } - return input; + return [name, locatorInfo]; } } diff --git a/src/loader/helpers.ts b/src/loader/helpers.ts index da3606f0..5234ae08 100644 --- a/src/loader/helpers.ts +++ b/src/loader/helpers.ts @@ -5,8 +5,8 @@ * view the LICENSE file that was distributed with this source code. */ +import { buildFilePath } from '../locator'; import type { LocatorInfo } from '../locator'; -import { buildFilePath } from '../utils'; import { useLoader } from './singleton'; import type { Loader, Rule } from './type'; diff --git a/src/loader/module.ts b/src/loader/module.ts index 8fb6d98c..69d535ab 100644 --- a/src/loader/module.ts +++ b/src/loader/module.ts @@ -6,8 +6,8 @@ */ import path from 'node:path'; -import { isFilePath, pathToLocatorInfo } from '../locator'; -import { buildFilePath } from '../utils'; +import { buildFilePath, pathToLocatorInfo } from '../locator'; +import { isFilePath } from '../utils'; import { JSONLoader, ModuleLoader } from './built-in'; import { LoaderId } from './constants'; import type { Loader, Rule } from './type'; diff --git a/src/locator/utils.ts b/src/locator/utils.ts index 813aa3b6..de9cf612 100644 --- a/src/locator/utils.ts +++ b/src/locator/utils.ts @@ -6,8 +6,8 @@ */ import path from 'node:path'; +import { isObject, toArray } from '../utils'; import type { LocatorInfo, LocatorOptions } from './type'; -import { toArray } from '../utils'; export function buildLocatorOptions(options?: Partial) : LocatorOptions { options = options || {}; @@ -23,11 +23,6 @@ export function buildLocatorOptions(options?: Partial) : Locator return options as LocatorOptions; } -export function isFilePath(input: string) { - const info = path.parse(input); - return info.ext !== ''; -} - export function pathToLocatorInfo( input: string, skipResolve?: boolean, @@ -47,3 +42,36 @@ export function pathToLocatorInfo( extension: info.ext, }; } + +export function isLocatorInfo( + input: unknown, +) : input is LocatorInfo { + return isObject(input) && + typeof input.path === 'string' && + typeof input.name === 'string' && + typeof input.extension === 'string'; +} + +export function buildFilePath(input: LocatorInfo | string) { + if (typeof input === 'string') { + return input; + } + + if (input.extension) { + return path.join(input.path, input.name) + input.extension; + } + + return path.join(input.path, input.name); +} + +export function buildFilePathWithoutExtension(input: LocatorInfo | string) { + let info: LocatorInfo; + + if (typeof input === 'string') { + info = pathToLocatorInfo(input); + } else { + info = input; + } + + return path.join(info.path, info.name); +} diff --git a/src/utils/file-path.ts b/src/utils/file-path.ts index b54bff85..470a33fd 100644 --- a/src/utils/file-path.ts +++ b/src/utils/file-path.ts @@ -5,29 +5,8 @@ * view the LICENSE file that was distributed with this source code. */ import path from 'node:path'; -import type { LocatorInfo } from '../locator'; -import { pathToLocatorInfo } from '../locator'; -export function buildFilePath(input: LocatorInfo | string) { - if (typeof input === 'string') { - return input; - } - - if (input.extension) { - return path.join(input.path, input.name) + input.extension; - } - - return path.join(input.path, input.name); -} - -export function buildFilePathWithoutExtension(input: LocatorInfo | string) { - let info: LocatorInfo; - - if (typeof input === 'string') { - info = pathToLocatorInfo(input); - } else { - info = input; - } - - return path.join(info.path, info.name); +export function isFilePath(input: string) { + const extension = path.extname(input); + return extension && extension !== ''; }