typescript-transform-paths
Version:
Transforms module resolution paths using TypeScript path mapping and/or custom paths
566 lines (555 loc) • 25.4 kB
JavaScript
import { createRequire } from "node:module";
import * as path$1 from "node:path";
import path from "node:path";
import { Minimatch } from "minimatch";
import ts, { Debug, ImportsNotUsedAsValues, isInJSFile, removeFileExtension, removeSuffix } from "typescript";
import url from "node:url";
import fs from "node:fs";
import * as os from "node:os";
//#region rolldown:runtime
var __require = /* @__PURE__ */ createRequire(import.meta.url);
//#endregion
//#region src/types.ts
const RunMode = {
TsNode: "ts-node",
Manual: "manual",
Program: "program"
};
const TsNodeState = {
Full: 0,
Stripped: 1
};
//#endregion
//#region src/utils/ts-helpers.ts
/** Determine output file path for source file */
function getOutputDirForSourceFile(context, sourceFile) {
const { tsInstance, emitHost, outputFileNamesCache, compilerOptions, tsInstance: { getOwnEmitOutputFilePath, getOutputExtension } } = context;
if (outputFileNamesCache.has(sourceFile)) return outputFileNamesCache.get(sourceFile);
const outputPath = sourceFile.path && sourceFile.resolvedPath && sourceFile.path !== sourceFile.resolvedPath ? sourceFile.resolvedPath : getOwnEmitOutputFilePath(sourceFile.fileName, emitHost, getOutputExtension(sourceFile.fileName, compilerOptions));
if (!outputPath) throw new Error(`Could not resolve output path for ${sourceFile.fileName}. Please report a GH issue at: https://github.com/LeDDGroup/typescript-transform-paths/issues`);
const res = path.dirname(outputPath);
outputFileNamesCache.set(sourceFile, res);
return tsInstance.normalizePath(res);
}
/** Determine if moduleName matches config in paths */
function isModulePathsMatch(context, moduleName) {
const { pathsPatterns, tsInstance: { matchPatternOrExact } } = context;
return !!(pathsPatterns && matchPatternOrExact(pathsPatterns, moduleName));
}
/** Create barebones EmitHost (for no-Program transform) */
function createSyntheticEmitHost(compilerOptions, tsInstance, getCanonicalFileName, fileNames) {
return {
getCompilerOptions: () => compilerOptions,
getCurrentDirectory: tsInstance.sys.getCurrentDirectory,
getCommonSourceDirectory: () => tsInstance.getCommonSourceDirectoryOfConfig({
options: compilerOptions,
fileNames
}, !tsInstance.sys.useCaseSensitiveFileNames),
getCanonicalFileName
};
}
/** Get ts-node register info */
function getTsNodeRegistrationProperties(tsInstance) {
let tsNodeSymbol;
try {
tsNodeSymbol = __require("ts-node")?.["REGISTER_INSTANCE"];
} catch {
return;
}
if (!global.process[tsNodeSymbol]) return;
const { config, options } = global.process[tsNodeSymbol];
const { configFilePath } = config.options;
const pcl = configFilePath ? tsInstance.getParsedCommandLineOfConfigFile(configFilePath, {}, tsInstance.sys) : void 0;
const fileNames = pcl?.fileNames || config.fileNames;
return {
compilerOptions: Object.assign({}, config.options, options.compilerOptions, { outDir: pcl?.options.outDir }),
fileNames,
tsNodeOptions: options
};
}
//#endregion
//#region src/utils/general-utils.ts
const isURL = (s) => !!s && (!!url.parse(s).host || !!url.parse(s).hostname);
const isBaseDir = (baseDir, testDir) => {
const relative = path.relative(baseDir, testDir);
return relative ? !relative.startsWith("..") && !path.isAbsolute(relative) : true;
};
const maybeAddRelativeLocalPrefix = (p) => p[0] === "." ? p : `./${p}`;
//#endregion
//#region src/utils/elide-import-export.ts
/**
* UPDATE:
*
* TODO - In next major version, we can remove this file entirely due to TS PR 57223
* https://github.com/microsoft/TypeScript/pull/57223
*
* This file and its contents are due to an issue in TypeScript (affecting _at least_ up to 4.1) which causes type
* elision to break during emit for nodes which have been transformed. Specifically, if the 'original' property is set,
* elision functionality no longer works.
*
* This results in module specifiers for types being output in import/export declarations in the compiled _JS files_
*
* The logic herein compensates for that issue by recreating type elision separately so that the transformer can update
* the clause with the properly elided information
*
* Issues:
*
* - See https://github.com/LeDDGroup/typescript-transform-paths/issues/184
* - See https://github.com/microsoft/TypeScript/issues/40603
* - See https://github.com/microsoft/TypeScript/issues/31446
*
* @example
* // a.ts
* export type A = string;
* export const B = 2;
*
* // b.ts
* import { A, B } from "./b";
* export { A } from "./b";
*
* // Expected output for b.js
* import { B } from "./b";
*
* // Actual output for b.js
* import { A, B } from "./b";
* export { A } from "./b";
*/
function elideImportOrExportDeclaration(context, node, newModuleSpecifier, resolver) {
const { tsInstance, factory } = context;
const { compilerOptions } = context;
const { visitNode, isNamedImportBindings, isImportSpecifier, SyntaxKind, visitNodes, isNamedExportBindings, isIdentifier, isExportSpecifier } = tsInstance;
const isNamespaceExport = tsInstance.isNamespaceExport ?? ((node$1) => node$1.kind === SyntaxKind.NamespaceExport);
if (tsInstance.isImportDeclaration(node)) {
if (!node.importClause) return node.importClause;
if (node.importClause.isTypeOnly) return void 0;
const importClause = visitNode(node.importClause, visitImportClause);
if (importClause || compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Preserve || compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Error) return factory.updateImportDeclaration(node, void 0, importClause, newModuleSpecifier, node.attributes || node.assertClause);
else return void 0;
} else {
if (node.isTypeOnly) return void 0;
if (!node.exportClause || node.exportClause.kind === SyntaxKind.NamespaceExport) return node;
const allowEmpty = !!compilerOptions["verbatimModuleSyntax"] || !!node.moduleSpecifier && (compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Preserve || compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Error);
const exportClause = visitNode(node.exportClause, ((bindings) => visitNamedExportBindings(bindings, allowEmpty)), isNamedExportBindings);
return exportClause ? factory.updateExportDeclaration(node, void 0, node.isTypeOnly, exportClause, newModuleSpecifier, node.attributes || node.assertClause) : void 0;
}
/**
* Visits an import clause, eliding it if it is not referenced.
*
* @param node The import clause node.
*/
function visitImportClause(node$1) {
const name = shouldEmitAliasDeclaration(node$1) ? node$1.name : void 0;
const namedBindings = visitNode(node$1.namedBindings, visitNamedImportBindings, isNamedImportBindings);
return name || namedBindings ? factory.updateImportClause(node$1, false, name, namedBindings) : void 0;
}
/**
* Visits named import bindings, eliding it if it is not referenced.
*
* @param node The named import bindings node.
*/
function visitNamedImportBindings(node$1) {
if (node$1.kind === SyntaxKind.NamespaceImport) return shouldEmitAliasDeclaration(node$1) ? node$1 : void 0;
else {
const allowEmpty = compilerOptions["verbatimModuleSyntax"] || compilerOptions.preserveValueImports && (compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Preserve || compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Error);
const elements = visitNodes(node$1.elements, visitImportSpecifier, isImportSpecifier);
return allowEmpty || tsInstance.some(elements) ? factory.updateNamedImports(node$1, elements) : void 0;
}
}
/**
* Visits an import specifier, eliding it if it is not referenced.
*
* @param node The import specifier node.
*/
function visitImportSpecifier(node$1) {
return !node$1.isTypeOnly && shouldEmitAliasDeclaration(node$1) ? node$1 : void 0;
}
/** Visits named exports, eliding it if it does not contain an export specifier that resolves to a value. */
function visitNamedExports(node$1, allowEmpty) {
const elements = visitNodes(node$1.elements, visitExportSpecifier, isExportSpecifier);
return allowEmpty || tsInstance.some(elements) ? factory.updateNamedExports(node$1, elements) : void 0;
}
function visitNamedExportBindings(node$1, allowEmpty) {
return isNamespaceExport(node$1) ? visitNamespaceExports(node$1) : visitNamedExports(node$1, allowEmpty);
}
function visitNamespaceExports(node$1) {
return factory.updateNamespaceExport(node$1, Debug.checkDefined(visitNode(node$1.name, (n) => n, isIdentifier)));
}
/**
* Visits an export specifier, eliding it if it does not resolve to a value.
*
* @param node The export specifier node.
*/
function visitExportSpecifier(node$1) {
return !node$1.isTypeOnly && (compilerOptions["verbatimModuleSyntax"] || resolver.isValueAliasDeclaration(node$1)) ? node$1 : void 0;
}
function shouldEmitAliasDeclaration(node$1) {
return !!compilerOptions["verbatimModuleSyntax"] || isInJSFile(node$1) || (compilerOptions.preserveValueImports ? resolver.isValueAliasDeclaration(node$1) : resolver.isReferencedAliasDeclaration(node$1));
}
}
//#endregion
//#region src/utils/get-relative-path.ts
let isCaseSensitiveFilesystem;
function tryRmFile(fileName) {
try {
if (fs.existsSync(fileName)) fs.rmSync(fileName, { force: true });
} catch {}
}
function getIsFsCaseSensitive() {
if (isCaseSensitiveFilesystem != void 0) return isCaseSensitiveFilesystem;
for (let i = 0; i < 1e3; i++) {
const tmpFileName = path.join(os.tmpdir(), `tstp~${i}.tmp`);
tryRmFile(tmpFileName);
try {
fs.writeFileSync(tmpFileName, "");
isCaseSensitiveFilesystem = !fs.existsSync(tmpFileName.replace("tstp", "TSTP"));
return isCaseSensitiveFilesystem;
} catch {} finally {
tryRmFile(tmpFileName);
}
}
console.warn(`Could not determine filesystem's case sensitivity. Please file a bug report with your system's details`);
isCaseSensitiveFilesystem = false;
return isCaseSensitiveFilesystem;
}
/** @private The Export is only for unit tests */
function getMatchPortion(from, to) {
const lowerFrom = from.toLocaleLowerCase();
const lowerTo = to.toLocaleLowerCase();
const maxLen = Math.max(lowerFrom.length, lowerTo.length);
let i = 0;
while (i < maxLen) {
if (lowerFrom[i] !== lowerTo[i]) break;
i++;
}
return to.slice(0, i);
}
function getRelativePath(from, to) {
try {
from = fs.realpathSync.native(from);
to = fs.realpathSync.native(to);
} catch {
if (!getIsFsCaseSensitive()) {
const matchPortion = getMatchPortion(from, to);
from = matchPortion + from.slice(matchPortion.length);
to = matchPortion + to.slice(matchPortion.length);
}
}
return path.relative(from, to);
}
//#endregion
//#region src/utils/resolve-module-name.ts
const IndexType = {
NonIndex: 0,
Explicit: 1,
Implicit: 2,
ImplicitPackage: 3
};
function getPathDetail(moduleName, resolvedModule) {
const resolvedFileName = resolvedModule.originalPath ?? resolvedModule.resolvedFileName;
const implicitPackageIndex = resolvedModule.packageId?.subModuleName;
const resolvedDir = implicitPackageIndex ? removeSuffix(resolvedFileName, `/${implicitPackageIndex}`) : path$1.dirname(resolvedFileName);
const resolvedBaseName = implicitPackageIndex ? void 0 : path$1.basename(resolvedFileName);
const resolvedBaseNameNoExtension = resolvedBaseName && removeFileExtension(resolvedBaseName);
const resolvedExtName = resolvedBaseName && path$1.extname(resolvedFileName);
let baseName = implicitPackageIndex ? void 0 : path$1.basename(moduleName);
let baseNameNoExtension = baseName && removeFileExtension(baseName);
let extName = baseName && path$1.extname(moduleName);
if (resolvedBaseNameNoExtension && baseName && resolvedBaseNameNoExtension === baseName) {
baseNameNoExtension = baseName;
extName = void 0;
}
const indexType = implicitPackageIndex ? IndexType.ImplicitPackage : baseNameNoExtension === "index" && resolvedBaseNameNoExtension === "index" ? IndexType.Explicit : baseNameNoExtension !== "index" && resolvedBaseNameNoExtension === "index" ? IndexType.Implicit : IndexType.NonIndex;
if (indexType === IndexType.Implicit) {
baseName = void 0;
baseNameNoExtension = void 0;
extName = void 0;
}
return {
baseName,
baseNameNoExtension,
extName,
resolvedBaseName,
resolvedBaseNameNoExtension,
resolvedExtName,
resolvedDir,
indexType,
implicitPackageIndex,
resolvedFileName
};
}
function getResolvedSourceFile(context, fileName) {
let res;
const { program, tsInstance } = context;
if (program) {
res = program.getSourceFile(fileName);
if (res) return res;
res = program.getSourceFiles().find((s) => removeFileExtension(s.fileName) === removeFileExtension(fileName));
if (res) return res;
}
return tsInstance.createSourceFile(fileName, ``, tsInstance.ScriptTarget.ESNext, false);
}
/** Resolve a module name */
function resolveModuleName(context, moduleName) {
const { tsInstance, compilerOptions, sourceFile, config, rootDirs } = context;
const { resolvedModule, failedLookupLocations } = tsInstance.resolveModuleName(moduleName, sourceFile.fileName, compilerOptions, tsInstance.sys);
if (!resolvedModule) {
const maybeURL = failedLookupLocations[0];
if (!isURL(maybeURL)) return void 0;
return {
isURL: true,
resolvedPath: void 0,
outputPath: maybeURL
};
}
const resolvedSourceFile = getResolvedSourceFile(context, resolvedModule.resolvedFileName);
const { indexType, resolvedBaseNameNoExtension, resolvedFileName, implicitPackageIndex, extName, resolvedDir } = getPathDetail(moduleName, resolvedModule);
let outputBaseName = resolvedBaseNameNoExtension ?? "";
if (indexType === IndexType.Implicit) outputBaseName = outputBaseName.replace(/(\/index$)|(^index$)/, "");
if (outputBaseName && extName) outputBaseName = `${outputBaseName}${extName}`;
let srcFileOutputDir = getOutputDirForSourceFile(context, sourceFile);
let moduleFileOutputDir = implicitPackageIndex ? resolvedDir : getOutputDirForSourceFile(context, resolvedSourceFile);
if (config.useRootDirs && rootDirs) {
let fileRootDir = "";
let moduleRootDir = "";
for (const rootDir of rootDirs) {
if (isBaseDir(rootDir, moduleFileOutputDir) && rootDir.length > moduleRootDir.length) moduleRootDir = rootDir;
if (isBaseDir(rootDir, srcFileOutputDir) && rootDir.length > fileRootDir.length) fileRootDir = rootDir;
}
if (fileRootDir && moduleRootDir) {
srcFileOutputDir = getRelativePath(fileRootDir, srcFileOutputDir);
moduleFileOutputDir = getRelativePath(moduleRootDir, moduleFileOutputDir);
}
}
const outputDir = getRelativePath(srcFileOutputDir, moduleFileOutputDir);
return {
isURL: false,
outputPath: maybeAddRelativeLocalPrefix(tsInstance.normalizePath(path$1.join(outputDir, outputBaseName))),
resolvedPath: resolvedFileName
};
}
//#endregion
//#region src/utils/resolve-path-update-node.ts
/** Gets proper path and calls updaterFn to get the new node if it should be updated */
function resolvePathAndUpdateNode(context, node, moduleName, updaterFn) {
const { sourceFile, tsInstance, factory } = context;
const { normalizePath } = tsInstance;
const tags = getStatementTags();
if (tags.shouldSkip) return node;
if (tags.overridePath) {
const transformedPath = isURL(tags.overridePath) ? tags.overridePath : maybeAddRelativeLocalPrefix(normalizePath(tags.overridePath));
return updaterFn(factory.createStringLiteral(transformedPath));
}
if (!isModulePathsMatch(context, moduleName)) return node;
const res = resolveModuleName(context, moduleName);
if (!res) return node;
const { outputPath, resolvedPath } = res;
if (context.excludeMatchers) {
for (const matcher of context.excludeMatchers) if (matcher.match(outputPath) || resolvedPath && matcher.match(resolvedPath)) return node;
}
return updaterFn(factory.createStringLiteral(outputPath));
function getStatementTags() {
let targetNode = tsInstance.isStatement(node) ? node : tsInstance.findAncestor(node, tsInstance.isStatement) ?? node;
targetNode = tsInstance.getOriginalNode(targetNode);
let jsDocTags;
try {
jsDocTags = tsInstance.getJSDocTags(targetNode);
} catch {}
const commentTags = /* @__PURE__ */ new Map();
if (targetNode.pos >= 0) try {
const trivia = targetNode.getFullText(sourceFile).slice(0, targetNode.getLeadingTriviaWidth(sourceFile));
const regex = /^\s*\/{2,3}\s*@(transform-path|no-transform-path)(?:[^\S\n\r](.+?))?$/gim;
for (let match = regex.exec(trivia); match; match = regex.exec(trivia)) if (match[1]) commentTags.set(match[1], match[2]);
} catch {}
const overridePath = findTag("transform-path");
const shouldSkip = findTag("no-transform-path");
return {
overridePath: typeof overridePath === "string" ? overridePath : void 0,
shouldSkip: !!shouldSkip
};
function findTag(expected) {
if (commentTags.has(expected)) return commentTags.get(expected) || true;
if (!jsDocTags?.length) return void 0;
for (const tag of jsDocTags) {
const tagName = tag.tagName.text.toLowerCase();
if (tagName === expected) return typeof tag.comment === "string" ? tag.comment : true;
if (typeof tag.comment !== "string" || tag.comment[0] !== "-") continue;
const dashPos = expected.indexOf("-");
if (dashPos < 0) return void 0;
if (tagName === expected.slice(0, dashPos)) {
const comment = tag.comment;
const choppedCommentTagName = comment.slice(0, expected.length - dashPos);
return choppedCommentTagName === expected.slice(dashPos) ? comment.slice(choppedCommentTagName.length + 1).trim() || true : void 0;
}
}
}
}
}
//#endregion
//#region src/visitor.ts
const isAsyncImport = ({ tsInstance }, node) => tsInstance.isCallExpression(node) && node.expression.kind === tsInstance.SyntaxKind.ImportKeyword && !!node.arguments[0] && tsInstance.isStringLiteral(node.arguments[0]) && node.arguments.length === 1;
const isRequire = ({ tsInstance }, node) => tsInstance.isCallExpression(node) && tsInstance.isIdentifier(node.expression) && node.expression.text === "require" && !!node.arguments[0] && tsInstance.isStringLiteral(node.arguments[0]) && node.arguments.length === 1;
/** Visit and replace nodes with module specifiers */
function nodeVisitor(node) {
const { factory, tsInstance, transformationContext } = this;
/**
* Update require / import functions
*
* @example
* require("module");
* import("module");
*/
if (isRequire(this, node) || isAsyncImport(this, node)) return resolvePathAndUpdateNode(this, node, node.arguments[0].text, (p) => {
const res = factory.updateCallExpression(node, node.expression, node.typeArguments, [p]);
const textNode = node.arguments[0];
if (!textNode) throw new Error("Expected textNode");
const commentRanges = tsInstance.getLeadingCommentRanges(textNode.getFullText(), 0) ?? [];
for (const range of commentRanges) {
const { kind, pos, end, hasTrailingNewLine } = range;
const caption = textNode.getFullText().substring(pos, end).replace(kind === tsInstance.SyntaxKind.MultiLineCommentTrivia ? /^\/\*(.+)\*\/.*/s : /^\/\/(.+)/s, "$1");
tsInstance.addSyntheticLeadingComment(p, kind, caption, hasTrailingNewLine);
}
return res;
});
/**
* Update ExternalModuleReference
*
* @example
* import foo = require("foo");
*/
if (tsInstance.isExternalModuleReference(node) && tsInstance.isStringLiteral(node.expression)) return resolvePathAndUpdateNode(this, node, node.expression.text, (p) => factory.updateExternalModuleReference(node, p));
/**
* Update ImportTypeNode
*
* @example
* typeof import("./bar");
* import("package").MyType;
*/
if (tsInstance.isImportTypeNode(node)) {
const argument = node.argument;
if (!tsInstance.isStringLiteral(argument.literal)) return node;
const { text } = argument.literal;
if (!text) return node;
const res = resolvePathAndUpdateNode(this, node, text, (p) => factory.updateImportTypeNode(node, factory.updateLiteralTypeNode(argument, p), node.assertions, node.qualifier, node.typeArguments, node.isTypeOf));
return tsInstance.visitEachChild(res, this.getVisitor(), transformationContext);
}
/**
* Update ImportDeclaration
*
* @example
* import ... 'module';
*/
if (tsInstance.isImportDeclaration(node) && node.moduleSpecifier && tsInstance.isStringLiteral(node.moduleSpecifier)) return resolvePathAndUpdateNode(this, node, node.moduleSpecifier.text, (p) => {
if (!this.isDeclarationFile && node.importClause?.namedBindings) {
const resolver = transformationContext.getEmitResolver();
if (resolver) return elideImportOrExportDeclaration(this, node, p, resolver);
}
return factory.updateImportDeclaration(node, node.modifiers, node.importClause, p, node.assertClause);
});
/**
* Update ExportDeclaration
*
* @example
* export ... 'module';
*/
if (tsInstance.isExportDeclaration(node) && node.moduleSpecifier && tsInstance.isStringLiteral(node.moduleSpecifier)) return resolvePathAndUpdateNode(this, node, node.moduleSpecifier.text, (p) => {
if (!this.isDeclarationFile && node.exportClause && tsInstance.isNamedExports(node.exportClause)) {
const resolver = transformationContext.getEmitResolver();
if (resolver) return elideImportOrExportDeclaration(this, node, p, resolver);
}
return factory.updateExportDeclaration(node, node.modifiers, node.isTypeOnly, node.exportClause, p, node.assertClause);
});
/** Update module augmentation */
if (tsInstance.isModuleDeclaration(node) && tsInstance.isStringLiteral(node.name)) return resolvePathAndUpdateNode(this, node, node.name.text, (p) => factory.updateModuleDeclaration(node, node.modifiers, p, node.body));
return tsInstance.visitEachChild(node, this.getVisitor(), transformationContext);
}
//#endregion
//#region src/transformer.ts
function getTsProperties(args) {
let fileNames;
let compilerOptions;
let runMode;
let tsNodeState;
const { 0: program, 2: extras, 3: manualTransformOptions } = args;
const tsInstance = extras?.ts ?? ts;
if (program) compilerOptions = program.getCompilerOptions();
const tsNodeProps = getTsNodeRegistrationProperties(tsInstance);
const isTsNode = tsNodeProps && (!program || compilerOptions.configFilePath === tsNodeProps.compilerOptions.configFilePath);
if (program && !isTsNode) {
runMode = RunMode.Program;
compilerOptions = compilerOptions;
} else if (manualTransformOptions) {
runMode = RunMode.Manual;
fileNames = manualTransformOptions.fileNames;
compilerOptions = manualTransformOptions.compilerOptions;
} else if (isTsNode) {
fileNames = tsNodeProps.fileNames;
runMode = RunMode.TsNode;
tsNodeState = !program || fileNames.length > 1 && program?.getRootFileNames().length === 1 || !compilerOptions.paths && tsNodeProps.compilerOptions.paths ? TsNodeState.Stripped : TsNodeState.Full;
compilerOptions = tsNodeState === TsNodeState.Full ? compilerOptions : {
...program?.getCompilerOptions(),
...tsNodeProps.compilerOptions
};
} else throw new Error("Cannot transform without a Program, ts-node instance, or manual parameters supplied. Make sure you're using ts-patch or ts-node with transpileOnly.");
return {
tsInstance,
compilerOptions,
fileNames,
runMode,
tsNodeState
};
}
function transformer(program, pluginConfig, transformerExtras, manualTransformOptions) {
return (transformationContext) => {
const { tsInstance, compilerOptions, fileNames, runMode, tsNodeState } = getTsProperties([
program,
pluginConfig,
transformerExtras,
manualTransformOptions
]);
const rootDirs = compilerOptions.rootDirs?.filter(path.isAbsolute);
const config = pluginConfig ?? {};
const getCanonicalFileName = tsInstance.createGetCanonicalFileName(tsInstance.sys.useCaseSensitiveFileNames);
let emitHost = transformationContext.getEmitHost();
if (!emitHost || tsNodeState === TsNodeState.Stripped) {
if (!fileNames) throw new Error(`No EmitHost found and could not determine files to be processed. Please file an issue with a reproduction!`);
emitHost = createSyntheticEmitHost(compilerOptions, tsInstance, getCanonicalFileName, fileNames);
}
const { configFile, paths } = compilerOptions;
const { tryParsePatterns } = tsInstance;
const [tsVersionMajor, tsVersionMinor] = tsInstance.versionMajorMinor.split(".").map((v) => +v);
if (tsVersionMajor === void 0 || tsVersionMinor === void 0) throw new Error("Expected version to be parsed");
const tsTransformPathsContext = {
compilerOptions,
config,
elisionMap: /* @__PURE__ */ new Map(),
tsFactory: transformationContext.factory,
program,
rootDirs,
transformationContext,
tsInstance,
tsVersionMajor,
tsVersionMinor,
emitHost,
runMode,
tsNodeState,
excludeMatchers: config.exclude?.map((globPattern) => new Minimatch(globPattern, { matchBase: true })),
outputFileNamesCache: /* @__PURE__ */ new Map(),
pathsPatterns: paths && (tryParsePatterns ? configFile?.configFileSpecs?.pathPatterns || tryParsePatterns(paths) : tsInstance.getOwnKeys(paths))
};
return (sourceFile) => {
const visitorContext = {
...tsTransformPathsContext,
sourceFile,
isDeclarationFile: sourceFile.isDeclarationFile,
originalSourceFile: ts.getParseTreeNode(sourceFile, ts.isSourceFile) || sourceFile,
getVisitor() {
return nodeVisitor.bind(this);
},
factory: tsTransformPathsContext.tsFactory ?? tsTransformPathsContext.tsInstance
};
return tsInstance.visitEachChild(sourceFile, visitorContext.getVisitor(), transformationContext);
};
};
}
//#endregion
export { transformer as t };