UNPKG

@nodejs-loaders/alias

Version:

Extend node to support TypeScript 'paths' via customization hooks.

84 lines (67 loc) 2.23 kB
import { readFile } from 'node:fs/promises'; import path from 'node:path'; import { pathToFileURL, URL } from 'node:url'; import JSON5 from 'json5'; const projectRoot = pathToFileURL(`${process.cwd()}/`); const aliases = await readConfigFile('tsconfig.json'); if (!aliases) console.warn( 'Alias loader was registered but no "paths" were found in tsconfig.json', 'This loader will behave as a noop (but you should probably remove it if you aren’t using it).', ); /** * @type {import('node:module').ResolveHook} */ function resolveAlias(specifier, ctx, next) { return (aliases ? resolveAliases : next)(specifier, ctx, next); } export { resolveAlias as resolve }; /** * @type {import('node:module').ResolveHook} */ export function resolveAliases(specifier, ctx, next) { // biome-ignore format: https://github.com/biomejs/biome/issues/4799 for (const [key, dest] of /** @type {AliasMap} */ (aliases)) { if (specifier === key) { return next(dest, ctx); } if (specifier.startsWith(key)) { return next(specifier.replace(key, dest), ctx); } } return next(specifier, ctx); } export function readConfigFile(filename) { const filepath = path.join(projectRoot.pathname, filename); return ( readFile(filepath) .then((contents) => contents.toString()) .then((contents) => JSON5.parse(contents)) // Get the `compilerOptions.paths` object from the parsed JSON .then((contents) => contents?.compilerOptions?.paths) .then(buildAliasMaps) .catch((err) => { if (err.code !== 'ENOENT') throw err; }) ); } /** * @typedef {Map<string, string>} AliasMap */ function buildAliasMaps(config) { if (!config) return; // biome-ignore format: https://github.com/biomejs/biome/issues/4799 const aliases = /** @type {AliasMap} */ (new Map()); for (const rawKey of Object.keys(config)) { const alias = config[rawKey][0]; const isPrefix = rawKey.endsWith('*'); const key = isPrefix ? rawKey.slice(0, -1) /* strip '*' */ : rawKey; const baseDest = isPrefix ? alias.slice(0, -1) /* strip '*' */ : alias; const dest = baseDest[0] === '/' || URL.canParse(baseDest) ? baseDest : new URL(baseDest, projectRoot).href; aliases.set(key, dest); } return aliases; }