blob: 7242ff7541f41ebc80dd9285c2879b618281716e [file] [log] [blame]
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'dart:io';
import 'package:package_config/package_config.dart';
import 'package:pub_semver/pub_semver.dart';
import 'profile.dart';
/// Caches the default language version that should be used for files within
/// directories.
///
/// The default language version for a Dart file is found by walking the parent
/// directories of the file being formatted to look for a
/// `.dart_tool/package_config.json` file. When found, we cache the result for
/// the formatted file's parent directory. This way, when formatting multiple
/// files in the same directory, we don't have to look for and read the package
/// config multiple times, which is slow.
///
/// (When formatting dart_style on a Mac laptop, it would spend as much time
/// looking for package configs for each file as it did formatting if we don't
/// cache. Caching makes it ~10x faster to find the language version for each
/// file.)
class LanguageVersionCache {
/// The previously cached default language version for all files immediately
/// within a given directory.
///
/// The version may be `null` if we formatted a file in that directory and
/// discovered that there is no surrounding package.
final Map<String, Version?> _directoryVersions = {};
/// Looks for a package surrounding [file] and, if found, returns the default
/// language version specified by that package.
Future<Version?> find(File file) async {
Profile.begin('look up package config');
try {
// Use the cached version (which may be `null`) if present.
var directory = file.parent.path;
if (_directoryVersions.containsKey(directory)) {
return _directoryVersions[directory];
}
// Otherwise, walk the file system and look for it.
var config = await findPackageConfig(file.parent);
if (config?.packageOf(file.absolute.uri)?.languageVersion
case var languageVersion?) {
// Store the version as pub_semver's [Version] type because that's
// what the analyzer parser uses, which is where the version
// ultimately gets used.
var version = Version(languageVersion.major, languageVersion.minor, 0);
return _directoryVersions[directory] = version;
}
// We weren't able to resolve this file's directory, so don't try again.
return _directoryVersions[directory] = null;
} finally {
Profile.end('look up package config');
}
}
}