blob: cd1fa3dd1256d2da7c42d5e1f5c0318c58474975 [file] [log] [blame]
// Copyright (c) 2017, 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.
/// Data structure storing an association between URI and file contents.
///
/// Each URI is also associated with a unique arbitrary path ending in ".dart".
/// This allows interfacing with analyzer code that expects to manipulate paths
/// rather than URIs.
class FileRepository {
/// Regular expression matching the arbitrary file paths generated by
/// [_pathForIndex].
static final _pathRegexp = new RegExp(r'^/[0-9]+\.dart$');
/// The URIs currently stored in the repository.
final _uris = <Uri>[];
/// Map from a URI to its index in [_uris].
final _uriToIndexMap = <Uri, int>{};
/// The file contents associated with the URIs in [_uris].
final _contents = <String>[];
/// Clear any contents stored in the file repository. The association between
/// URI and arbitrary path is preserved.
///
/// Subsequent calls to [contentsForPath] will have undefined results until
/// new contents are stored using [store].
void clearContents() {
for (var i = 0; i < _contents.length; i++) {
_contents[i] = null;
}
}
/// Return the contents of the file whose arbitrary path is [path].
///
/// The path must have been returned by a previous call to [store] or
/// [pathForUri].
String contentsForPath(String path) {
var contents = _contents[_indexForPath(path)];
assert(contents != null);
return contents;
}
/// For testing purposes, return the contents of all files stored in the file
/// repository, as a map from path to contents string.
Map<String, String> getContentsForTesting() {
var result = <String, String>{};
for (var i = 0; i < _contents.length; i++) {
if (_contents[i] != null) result[_pathForIndex(i)] = _contents[i];
}
return result;
}
/// Return the arbitrary path associated with [uri].
///
/// If [allocate] is `false` (the default), the uri must have previously been
/// allocated a corresponding path, e.g. via a call to [store]. If [allocate]
/// is `true`, then a new path will be allocated if necessary.
String pathForUri(Uri uri, {bool allocate: false}) {
return _pathForIndex(_indexForUri(uri, allocate));
}
/// Associate the given [uri] with file [contents].
///
/// The arbitrary path associated with the file is returned.
String store(Uri uri, String contents) {
int index = _indexForUri(uri, true);
_contents[index] = contents;
return _pathForIndex(index);
}
/// Return the URI for the file whose arbitrary path is [path].
///
/// The path must have been returned by a previous call to [store] or
/// [pathForUri].
Uri uriForPath(String path) => _uris[_indexForPath(path)];
/// Return the index into [_uris] and [_contents] matching the arbitrary path
/// [path].
int _indexForPath(String path) {
assert(_pathRegexp.hasMatch(path));
return int.parse(path.substring(1, path.length - 5));
}
int _indexForUri(Uri uri, bool allocate) {
int index = _uriToIndexMap[uri];
assert(allocate || index != null);
if (index == null) {
index = _uris.length;
_uris.add(uri);
_uriToIndexMap[uri] = index;
_contents.add(null);
}
return index;
}
/// Return the arbitrary path associated with the given index.
String _pathForIndex(int index) => '/$index.dart';
}