143 lines
7.4 KiB
JavaScript
143 lines
7.4 KiB
JavaScript
|
"use strict";
|
||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||
|
exports.createResolverFunctions = void 0;
|
||
|
const path_1 = require("path");
|
||
|
/**
|
||
|
* @internal
|
||
|
* In a factory because these are shared across both CompilerHost and LanguageService codepaths
|
||
|
*/
|
||
|
function createResolverFunctions(kwargs) {
|
||
|
const { host, ts, config, cwd, getCanonicalFileName, projectLocalResolveHelper, options, extensions, } = kwargs;
|
||
|
const moduleResolutionCache = ts.createModuleResolutionCache(cwd, getCanonicalFileName, config.options);
|
||
|
const knownInternalFilenames = new Set();
|
||
|
/** "Buckets" (module directories) whose contents should be marked "internal" */
|
||
|
const internalBuckets = new Set();
|
||
|
// Get bucket for a source filename. Bucket is the containing `./node_modules/*/` directory
|
||
|
// For '/project/node_modules/foo/node_modules/bar/lib/index.js' bucket is '/project/node_modules/foo/node_modules/bar/'
|
||
|
// For '/project/node_modules/foo/node_modules/@scope/bar/lib/index.js' bucket is '/project/node_modules/foo/node_modules/@scope/bar/'
|
||
|
const moduleBucketRe = /.*\/node_modules\/(?:@[^\/]+\/)?[^\/]+\//;
|
||
|
function getModuleBucket(filename) {
|
||
|
const find = moduleBucketRe.exec(filename);
|
||
|
if (find)
|
||
|
return find[0];
|
||
|
return '';
|
||
|
}
|
||
|
// Mark that this file and all siblings in its bucket should be "internal"
|
||
|
function markBucketOfFilenameInternal(filename) {
|
||
|
internalBuckets.add(getModuleBucket(filename));
|
||
|
}
|
||
|
function isFileInInternalBucket(filename) {
|
||
|
return internalBuckets.has(getModuleBucket(filename));
|
||
|
}
|
||
|
function isFileKnownToBeInternal(filename) {
|
||
|
return knownInternalFilenames.has(filename);
|
||
|
}
|
||
|
/**
|
||
|
* If we need to emit JS for a file, force TS to consider it non-external
|
||
|
*/
|
||
|
const fixupResolvedModule = (resolvedModule) => {
|
||
|
const { resolvedFileName } = resolvedModule;
|
||
|
if (resolvedFileName === undefined)
|
||
|
return;
|
||
|
// [MUST_UPDATE_FOR_NEW_FILE_EXTENSIONS]
|
||
|
// .ts,.mts,.cts is always switched to internal
|
||
|
// .js is switched on-demand
|
||
|
if (resolvedModule.isExternalLibraryImport &&
|
||
|
((resolvedFileName.endsWith('.ts') &&
|
||
|
!resolvedFileName.endsWith('.d.ts')) ||
|
||
|
(resolvedFileName.endsWith('.cts') &&
|
||
|
!resolvedFileName.endsWith('.d.cts')) ||
|
||
|
(resolvedFileName.endsWith('.mts') &&
|
||
|
!resolvedFileName.endsWith('.d.mts')) ||
|
||
|
isFileKnownToBeInternal(resolvedFileName) ||
|
||
|
isFileInInternalBucket(resolvedFileName))) {
|
||
|
resolvedModule.isExternalLibraryImport = false;
|
||
|
}
|
||
|
if (!resolvedModule.isExternalLibraryImport) {
|
||
|
knownInternalFilenames.add(resolvedFileName);
|
||
|
}
|
||
|
};
|
||
|
/*
|
||
|
* NOTE:
|
||
|
* Older ts versions do not pass `redirectedReference` nor `options`.
|
||
|
* We must pass `redirectedReference` to newer ts versions, but cannot rely on `options`, hence the weird argument name
|
||
|
*/
|
||
|
const resolveModuleNames = (moduleNames, containingFile, reusedNames, redirectedReference, optionsOnlyWithNewerTsVersions, containingSourceFile) => {
|
||
|
return moduleNames.map((moduleName, i) => {
|
||
|
var _a, _b;
|
||
|
const mode = containingSourceFile
|
||
|
? (_b = (_a = ts).getModeForResolutionAtIndex) === null || _b === void 0 ? void 0 : _b.call(_a, containingSourceFile, i)
|
||
|
: undefined;
|
||
|
let { resolvedModule } = ts.resolveModuleName(moduleName, containingFile, config.options, host, moduleResolutionCache, redirectedReference, mode);
|
||
|
if (!resolvedModule && options.experimentalTsImportSpecifiers) {
|
||
|
const lastDotIndex = moduleName.lastIndexOf('.');
|
||
|
const ext = lastDotIndex >= 0 ? moduleName.slice(lastDotIndex) : '';
|
||
|
if (ext) {
|
||
|
const replacements = extensions.tsResolverEquivalents.get(ext);
|
||
|
for (const replacementExt of replacements !== null && replacements !== void 0 ? replacements : []) {
|
||
|
({ resolvedModule } = ts.resolveModuleName(moduleName.slice(0, -ext.length) + replacementExt, containingFile, config.options, host, moduleResolutionCache, redirectedReference, mode));
|
||
|
if (resolvedModule)
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (resolvedModule) {
|
||
|
fixupResolvedModule(resolvedModule);
|
||
|
}
|
||
|
return resolvedModule;
|
||
|
});
|
||
|
};
|
||
|
// language service never calls this, but TS docs recommend that we implement it
|
||
|
const getResolvedModuleWithFailedLookupLocationsFromCache = (moduleName, containingFile, resolutionMode) => {
|
||
|
const ret = ts.resolveModuleNameFromCache(moduleName, containingFile, moduleResolutionCache, resolutionMode);
|
||
|
if (ret && ret.resolvedModule) {
|
||
|
fixupResolvedModule(ret.resolvedModule);
|
||
|
}
|
||
|
return ret;
|
||
|
};
|
||
|
const resolveTypeReferenceDirectives = (typeDirectiveNames, containingFile, redirectedReference, options, containingFileMode // new impliedNodeFormat is accepted by compilerHost
|
||
|
) => {
|
||
|
// Note: seems to be called with empty typeDirectiveNames array for all files.
|
||
|
// TODO consider using `ts.loadWithTypeDirectiveCache`
|
||
|
return typeDirectiveNames.map((typeDirectiveName) => {
|
||
|
// Copy-pasted from TS source:
|
||
|
const nameIsString = typeof typeDirectiveName === 'string';
|
||
|
const mode = nameIsString
|
||
|
? undefined
|
||
|
: ts.getModeForFileReference(typeDirectiveName, containingFileMode);
|
||
|
const strName = nameIsString
|
||
|
? typeDirectiveName
|
||
|
: typeDirectiveName.fileName.toLowerCase();
|
||
|
let { resolvedTypeReferenceDirective } = ts.resolveTypeReferenceDirective(strName, containingFile, config.options, host, redirectedReference, undefined, mode);
|
||
|
if (typeDirectiveName === 'node' && !resolvedTypeReferenceDirective) {
|
||
|
// Resolve @types/node relative to project first, then __dirname (copy logic from elsewhere / refactor into reusable function)
|
||
|
let typesNodePackageJsonPath;
|
||
|
try {
|
||
|
typesNodePackageJsonPath = projectLocalResolveHelper('@types/node/package.json', true);
|
||
|
}
|
||
|
catch { } // gracefully do nothing when @types/node is not installed for any reason
|
||
|
if (typesNodePackageJsonPath) {
|
||
|
const typeRoots = [(0, path_1.resolve)(typesNodePackageJsonPath, '../..')];
|
||
|
({ resolvedTypeReferenceDirective } =
|
||
|
ts.resolveTypeReferenceDirective(typeDirectiveName, containingFile, {
|
||
|
...config.options,
|
||
|
typeRoots,
|
||
|
}, host, redirectedReference));
|
||
|
}
|
||
|
}
|
||
|
if (resolvedTypeReferenceDirective) {
|
||
|
fixupResolvedModule(resolvedTypeReferenceDirective);
|
||
|
}
|
||
|
return resolvedTypeReferenceDirective;
|
||
|
});
|
||
|
};
|
||
|
return {
|
||
|
resolveModuleNames,
|
||
|
getResolvedModuleWithFailedLookupLocationsFromCache,
|
||
|
resolveTypeReferenceDirectives,
|
||
|
isFileKnownToBeInternal,
|
||
|
markBucketOfFilenameInternal,
|
||
|
};
|
||
|
}
|
||
|
exports.createResolverFunctions = createResolverFunctions;
|
||
|
//# sourceMappingURL=resolver-functions.js.map
|