UNPKG

7.57 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.createResolverFunctions = void 0;
4const path_1 = require("path");
5/**
6 * @internal
7 * In a factory because these are shared across both CompilerHost and LanguageService codepaths
8 */
9function createResolverFunctions(kwargs) {
10 const { host, ts, config, cwd, getCanonicalFileName, projectLocalResolveHelper, options, extensions, } = kwargs;
11 const moduleResolutionCache = ts.createModuleResolutionCache(cwd, getCanonicalFileName, config.options);
12 const knownInternalFilenames = new Set();
13 /** "Buckets" (module directories) whose contents should be marked "internal" */
14 const internalBuckets = new Set();
15 // Get bucket for a source filename. Bucket is the containing `./node_modules/*/` directory
16 // For '/project/node_modules/foo/node_modules/bar/lib/index.js' bucket is '/project/node_modules/foo/node_modules/bar/'
17 // For '/project/node_modules/foo/node_modules/@scope/bar/lib/index.js' bucket is '/project/node_modules/foo/node_modules/@scope/bar/'
18 const moduleBucketRe = /.*\/node_modules\/(?:@[^\/]+\/)?[^\/]+\//;
19 function getModuleBucket(filename) {
20 const find = moduleBucketRe.exec(filename);
21 if (find)
22 return find[0];
23 return '';
24 }
25 // Mark that this file and all siblings in its bucket should be "internal"
26 function markBucketOfFilenameInternal(filename) {
27 internalBuckets.add(getModuleBucket(filename));
28 }
29 function isFileInInternalBucket(filename) {
30 return internalBuckets.has(getModuleBucket(filename));
31 }
32 function isFileKnownToBeInternal(filename) {
33 return knownInternalFilenames.has(filename);
34 }
35 /**
36 * If we need to emit JS for a file, force TS to consider it non-external
37 */
38 const fixupResolvedModule = (resolvedModule) => {
39 const { resolvedFileName } = resolvedModule;
40 if (resolvedFileName === undefined)
41 return;
42 // [MUST_UPDATE_FOR_NEW_FILE_EXTENSIONS]
43 // .ts,.mts,.cts is always switched to internal
44 // .js is switched on-demand
45 if (resolvedModule.isExternalLibraryImport &&
46 ((resolvedFileName.endsWith('.ts') &&
47 !resolvedFileName.endsWith('.d.ts')) ||
48 (resolvedFileName.endsWith('.cts') &&
49 !resolvedFileName.endsWith('.d.cts')) ||
50 (resolvedFileName.endsWith('.mts') &&
51 !resolvedFileName.endsWith('.d.mts')) ||
52 isFileKnownToBeInternal(resolvedFileName) ||
53 isFileInInternalBucket(resolvedFileName))) {
54 resolvedModule.isExternalLibraryImport = false;
55 }
56 if (!resolvedModule.isExternalLibraryImport) {
57 knownInternalFilenames.add(resolvedFileName);
58 }
59 };
60 /*
61 * NOTE:
62 * Older ts versions do not pass `redirectedReference` nor `options`.
63 * We must pass `redirectedReference` to newer ts versions, but cannot rely on `options`, hence the weird argument name
64 */
65 const resolveModuleNames = (moduleNames, containingFile, reusedNames, redirectedReference, optionsOnlyWithNewerTsVersions, containingSourceFile) => {
66 return moduleNames.map((moduleName, i) => {
67 var _a, _b;
68 const mode = containingSourceFile
69 ? (_b = (_a = ts).getModeForResolutionAtIndex) === null || _b === void 0 ? void 0 : _b.call(_a, containingSourceFile, i)
70 : undefined;
71 let { resolvedModule } = ts.resolveModuleName(moduleName, containingFile, config.options, host, moduleResolutionCache, redirectedReference, mode);
72 if (!resolvedModule && options.experimentalTsImportSpecifiers) {
73 const lastDotIndex = moduleName.lastIndexOf('.');
74 const ext = lastDotIndex >= 0 ? moduleName.slice(lastDotIndex) : '';
75 if (ext) {
76 const replacements = extensions.tsResolverEquivalents.get(ext);
77 for (const replacementExt of replacements !== null && replacements !== void 0 ? replacements : []) {
78 ({ resolvedModule } = ts.resolveModuleName(moduleName.slice(0, -ext.length) + replacementExt, containingFile, config.options, host, moduleResolutionCache, redirectedReference, mode));
79 if (resolvedModule)
80 break;
81 }
82 }
83 }
84 if (resolvedModule) {
85 fixupResolvedModule(resolvedModule);
86 }
87 return resolvedModule;
88 });
89 };
90 // language service never calls this, but TS docs recommend that we implement it
91 const getResolvedModuleWithFailedLookupLocationsFromCache = (moduleName, containingFile, resolutionMode) => {
92 const ret = ts.resolveModuleNameFromCache(moduleName, containingFile, moduleResolutionCache, resolutionMode);
93 if (ret && ret.resolvedModule) {
94 fixupResolvedModule(ret.resolvedModule);
95 }
96 return ret;
97 };
98 const resolveTypeReferenceDirectives = (typeDirectiveNames, containingFile, redirectedReference, options, containingFileMode // new impliedNodeFormat is accepted by compilerHost
99 ) => {
100 // Note: seems to be called with empty typeDirectiveNames array for all files.
101 // TODO consider using `ts.loadWithTypeDirectiveCache`
102 return typeDirectiveNames.map((typeDirectiveName) => {
103 // Copy-pasted from TS source:
104 const nameIsString = typeof typeDirectiveName === 'string';
105 const mode = nameIsString
106 ? undefined
107 : ts.getModeForFileReference(typeDirectiveName, containingFileMode);
108 const strName = nameIsString
109 ? typeDirectiveName
110 : typeDirectiveName.fileName.toLowerCase();
111 let { resolvedTypeReferenceDirective } = ts.resolveTypeReferenceDirective(strName, containingFile, config.options, host, redirectedReference, undefined, mode);
112 if (typeDirectiveName === 'node' && !resolvedTypeReferenceDirective) {
113 // Resolve @types/node relative to project first, then __dirname (copy logic from elsewhere / refactor into reusable function)
114 let typesNodePackageJsonPath;
115 try {
116 typesNodePackageJsonPath = projectLocalResolveHelper('@types/node/package.json', true);
117 }
118 catch { } // gracefully do nothing when @types/node is not installed for any reason
119 if (typesNodePackageJsonPath) {
120 const typeRoots = [(0, path_1.resolve)(typesNodePackageJsonPath, '../..')];
121 ({ resolvedTypeReferenceDirective } =
122 ts.resolveTypeReferenceDirective(typeDirectiveName, containingFile, {
123 ...config.options,
124 typeRoots,
125 }, host, redirectedReference));
126 }
127 }
128 if (resolvedTypeReferenceDirective) {
129 fixupResolvedModule(resolvedTypeReferenceDirective);
130 }
131 return resolvedTypeReferenceDirective;
132 });
133 };
134 return {
135 resolveModuleNames,
136 getResolvedModuleWithFailedLookupLocationsFromCache,
137 resolveTypeReferenceDirectives,
138 isFileKnownToBeInternal,
139 markBucketOfFilenameInternal,
140 };
141}
142exports.createResolverFunctions = createResolverFunctions;
143//# sourceMappingURL=resolver-functions.js.map
\No newline at end of file