Skip to content

Commit 123b7c3

Browse files
Move caching to tryParsePatterns, avoid creating an intermediate array entirely.
1 parent 4a88ba6 commit 123b7c3

4 files changed

Lines changed: 67 additions & 54 deletions

File tree

src/compiler/commandLineParser.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3042,7 +3042,6 @@ function parseJsonConfigFileContentWorker(
30423042
validatedFilesSpecBeforeSubstitution,
30433043
validatedIncludeSpecsBeforeSubstitution,
30443044
validatedExcludeSpecsBeforeSubstitution,
3045-
pathPatterns: undefined, // Initialized on first use
30463045
isDefaultIncludeSpec,
30473046
};
30483047
}

src/compiler/moduleNameResolver.ts

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,9 @@ import {
7979
normalizeSlashes,
8080
PackageId,
8181
packageIdToString,
82+
ParsedPatterns,
8283
Path,
8384
pathIsRelative,
84-
Pattern,
8585
patternText,
8686
readJson,
8787
removeExtension,
@@ -1559,7 +1559,7 @@ function tryLoadModuleUsingOptionalResolutionSettings(extensions: Extensions, mo
15591559
}
15601560

15611561
function tryLoadModuleUsingPathsIfEligible(extensions: Extensions, moduleName: string, loader: ResolutionKindSpecificLoader, state: ModuleResolutionState) {
1562-
const { baseUrl, paths, configFile } = state.compilerOptions;
1562+
const { baseUrl, paths } = state.compilerOptions;
15631563
if (paths && !pathIsRelative(moduleName)) {
15641564
if (state.traceEnabled) {
15651565
if (baseUrl) {
@@ -1568,7 +1568,8 @@ function tryLoadModuleUsingPathsIfEligible(extensions: Extensions, moduleName: s
15681568
trace(state.host, Diagnostics.paths_option_is_specified_looking_for_a_pattern_to_match_module_name_0, moduleName);
15691569
}
15701570
const baseDirectory = getPathsBasePath(state.compilerOptions, state.host)!; // Always defined when 'paths' is defined
1571-
const pathPatterns = configFile?.configFileSpecs ? configFile.configFileSpecs.pathPatterns ??= tryParsePatterns(paths) : undefined;
1571+
// TODO: do we need to sort by aggregate length?
1572+
const pathPatterns = tryParsePatterns(paths);
15721573
return tryLoadModuleUsingPaths(extensions, moduleName, baseDirectory, paths, pathPatterns, loader, /*onlyRecordFailures*/ false, state);
15731574
}
15741575
}
@@ -2524,7 +2525,9 @@ function loadNodeModuleFromDirectoryWorker(extensions: Extensions, candidate: st
25242525
if (state.traceEnabled) {
25252526
trace(state.host, Diagnostics.package_json_has_a_typesVersions_entry_0_that_matches_compiler_version_1_looking_for_a_pattern_to_match_module_name_2, versionPaths.version, version, moduleName);
25262527
}
2527-
const result = tryLoadModuleUsingPaths(extensions, moduleName, candidate, versionPaths.paths, /*pathPatterns*/ undefined, loader, onlyRecordFailuresForPackageFile || onlyRecordFailuresForIndex, state);
2528+
// TODO: do we need to sort by aggregate length?
2529+
const pathPatterns = tryParsePatterns(versionPaths.paths);
2530+
const result = tryLoadModuleUsingPaths(extensions, moduleName, candidate, versionPaths.paths, pathPatterns, loader, onlyRecordFailuresForPackageFile || onlyRecordFailuresForIndex, state);
25282531
if (result) {
25292532
return removeIgnoredPackageId(result.value);
25302533
}
@@ -3118,22 +3121,17 @@ function loadModuleFromSpecificNodeModulesDirectory(extensions: Extensions, modu
31183121
trace(state.host, Diagnostics.package_json_has_a_typesVersions_entry_0_that_matches_compiler_version_1_looking_for_a_pattern_to_match_module_name_2, versionPaths.version, version, rest);
31193122
}
31203123
const packageDirectoryExists = nodeModulesDirectoryExists && directoryProbablyExists(packageDirectory, state.host);
3121-
const fromPaths = tryLoadModuleUsingPaths(extensions, rest, packageDirectory, versionPaths.paths, /*pathPatterns*/ undefined, loader, !packageDirectoryExists, state);
3124+
// TODO: do we need to sort by aggregate length?
3125+
const pathPatterns = tryParsePatterns(versionPaths.paths);
3126+
const fromPaths = tryLoadModuleUsingPaths(extensions, rest, packageDirectory, versionPaths.paths, pathPatterns, loader, !packageDirectoryExists, state);
31223127
if (fromPaths) {
31233128
return fromPaths.value;
31243129
}
31253130
}
31263131
return loader(extensions, candidate, !nodeModulesDirectoryExists, state);
31273132
}
31283133

3129-
const pathsToPatternsCache = new WeakMap<MapLike<string[]>, readonly (string | Pattern)[]>();
3130-
3131-
function tryLoadModuleUsingPaths(extensions: Extensions, moduleName: string, baseDirectory: string, paths: MapLike<string[]>, pathPatterns: readonly (string | Pattern)[] | undefined, loader: ResolutionKindSpecificLoader, onlyRecordFailures: boolean, state: ModuleResolutionState): SearchResult<Resolved> {
3132-
pathPatterns ??= pathsToPatternsCache.get(paths);
3133-
if (pathPatterns === undefined) {
3134-
pathsToPatternsCache.set(paths, pathPatterns = tryParsePatterns(paths));
3135-
}
3136-
3134+
function tryLoadModuleUsingPaths(extensions: Extensions, moduleName: string, baseDirectory: string, paths: MapLike<string[]>, pathPatterns: ParsedPatterns, loader: ResolutionKindSpecificLoader, onlyRecordFailures: boolean, state: ModuleResolutionState): SearchResult<Resolved> {
31373135
const matchedPattern = matchPatternOrExact(pathPatterns, moduleName);
31383136
if (matchedPattern) {
31393137
const matchedStar = isString(matchedPattern) ? undefined : matchedText(matchedPattern, moduleName);

src/compiler/types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7512,7 +7512,6 @@ export interface ConfigFileSpecs {
75127512
validatedFilesSpecBeforeSubstitution: readonly string[] | undefined;
75137513
validatedIncludeSpecsBeforeSubstitution: readonly string[] | undefined;
75147514
validatedExcludeSpecsBeforeSubstitution: readonly string[] | undefined;
7515-
pathPatterns: readonly (string | Pattern)[] | undefined;
75167515
isDefaultIncludeSpec: boolean;
75177516
}
75187517

src/compiler/utilities.ts

Lines changed: 56 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -10006,8 +10006,57 @@ export function tryParsePattern(pattern: string): string | Pattern | undefined {
1000610006
}
1000710007

1000810008
/** @internal */
10009-
export function tryParsePatterns(paths: MapLike<string[]>): (string | Pattern)[] {
10010-
return mapDefined(getOwnKeys(paths), path => tryParsePattern(path));
10009+
export interface ParsedPatterns {
10010+
matchableStringSet: ReadonlySet<string> | undefined;
10011+
sortedPatterns: (readonly Pattern[]) | undefined;
10012+
}
10013+
10014+
const parsedPatternsCache = new WeakMap<MapLike<string[]>, ParsedPatterns>();
10015+
10016+
/**
10017+
* Divides patterns into a set of exact specifiers and sorted patterns.
10018+
* NOTE that this function caches, and assumes the same `paths` argument will
10019+
* never be provided with a different value for `sortByAggregateLength`.
10020+
*
10021+
* @internal
10022+
**/
10023+
export function tryParsePatterns(paths: MapLike<string[]>, sortByAggregateLength: boolean = false): ParsedPatterns {
10024+
let result = parsedPatternsCache.get(paths)
10025+
if (result !== undefined) {
10026+
return result;
10027+
}
10028+
10029+
let matchableStringSet: Set<string> | undefined;
10030+
let sortedPatterns: Pattern[] | undefined;
10031+
10032+
const pathList = getOwnKeys(paths);
10033+
for (const path of pathList) {
10034+
const patternOrStr = tryParsePattern(path)
10035+
if (patternOrStr === undefined) {
10036+
continue;
10037+
}
10038+
else if (typeof patternOrStr === "string") {
10039+
(matchableStringSet ??= new Set()).add(patternOrStr);
10040+
}
10041+
else {
10042+
(sortedPatterns ??= []).push(patternOrStr);
10043+
}
10044+
}
10045+
10046+
sortedPatterns?.sort((a, b) => {
10047+
const prefixComparison = compareStringsCaseSensitive(a.prefix, b.prefix)
10048+
if (prefixComparison === 0 && sortByAggregateLength) {
10049+
return a.suffix.length - b.suffix.length;
10050+
}
10051+
return prefixComparison;
10052+
});
10053+
10054+
parsedPatternsCache.set(paths, result = {
10055+
matchableStringSet,
10056+
sortedPatterns,
10057+
});
10058+
10059+
return result;
1001110060
}
1001210061

1001310062
/** @internal */
@@ -10063,53 +10112,21 @@ export const emptyFileSystemEntries: FileSystemEntries = {
1006310112
directories: emptyArray,
1006410113
};
1006510114

10066-
interface MatchPatternOrExactCacheEntry {
10067-
matchableStringSet: Set<string>;
10068-
sortedPatterns: Pattern[];
10069-
}
10070-
10071-
const patternOrStringsCache = new WeakMap<readonly (string | Pattern)[], MatchPatternOrExactCacheEntry>();
10072-
1007310115
/**
1007410116
* patternOrStrings contains both patterns (containing "*") and regular strings.
1007510117
* Return an exact match if possible, or a pattern match, or undefined.
1007610118
* (These are verified by verifyCompilerOptions to have 0 or 1 "*" characters.)
1007710119
*
1007810120
* @internal
1007910121
*/
10080-
export function matchPatternOrExact(patternOrStrings: readonly (string | Pattern)[], candidate: string): string | Pattern | undefined {
10081-
let matchableStringSet: Set<string>;
10082-
let sortedPatterns: Pattern[];
10083-
10084-
const cacheEntry = patternOrStringsCache.get(patternOrStrings);
10085-
if (cacheEntry !== undefined) {
10086-
({ matchableStringSet, sortedPatterns } = cacheEntry);
10087-
}
10088-
else {
10089-
matchableStringSet = new Set();
10090-
sortedPatterns = [];
10091-
10092-
for (const patternOrString of patternOrStrings) {
10093-
if (typeof patternOrString === "string") {
10094-
matchableStringSet.add(patternOrString);
10095-
}
10096-
else {
10097-
sortedPatterns.push(patternOrString);
10098-
}
10099-
}
10100-
10101-
sortedPatterns.sort((a, b) => compareStringsCaseSensitive(a.prefix, b.prefix));
10122+
export function matchPatternOrExact(patternOrStrings: ParsedPatterns, candidate: string): string | Pattern | undefined {
10123+
const { matchableStringSet, sortedPatterns } = patternOrStrings;
1010210124

10103-
patternOrStringsCache.set(patternOrStrings, {
10104-
matchableStringSet,
10105-
sortedPatterns,
10106-
});
10107-
}
10108-
10109-
if (matchableStringSet.has(candidate)) {
10125+
if (matchableStringSet?.has(candidate)) {
1011010126
return candidate;
1011110127
}
10112-
if (sortedPatterns.length === 0) {
10128+
10129+
if (sortedPatterns === undefined || sortedPatterns.length === 0) {
1011310130
return undefined;
1011410131
}
1011510132

0 commit comments

Comments
 (0)