// Copyright (c) 2016, 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:collection'; import 'package:analyzer/file_system/file_system.dart'; import 'package:analyzer/source/source.dart'; import 'package:analyzer/src/generated/engine.dart'; /// A source that represents a file. class FileSource extends Source { /// Map from encoded URI/filepath pair to a unique integer identifier. This /// identifier is used for equality tests and hash codes. /// /// The URI and filepath are joined into a pair by separating them with an '@' /// character. static final Map _idTable = HashMap(); /// The URI from which this source was originally derived. @override final Uri uri; /// The unique ID associated with this source. final int id; /// The file represented by this source. final File file; /// The cached absolute path of this source. String? _absolutePath; /// Initialize a newly created source object to represent the given [file]. If /// a [uri] is given, then it will be used as the URI from which the source /// was derived, otherwise a `file:` URI will be created based on the [file]. FileSource(this.file, [Uri? uri]) : uri = uri ?? file.toUri(), id = _idTable.putIfAbsent( '${uri ?? file.toUri()}@${file.path}', () => _idTable.length, ); @override TimestampedData get contents { return contentsFromFile; } /// Get and return the contents and timestamp of the underlying file. /// /// Clients should consider using the method /// `AnalysisSession.getFile('...').contents` because contexts can have local /// overrides of the content of a source that the source is not aware of. /// /// Throws an exception if the contents of this source could not be accessed. /// See [contents]. TimestampedData get contentsFromFile { return TimestampedData( file.modificationStamp, file.readAsStringSync(), ); } @override String get fullName => _absolutePath ??= file.path; @override int get hashCode => uri.hashCode; @override String get shortName => file.shortName; @override bool operator ==(Object other) { if (other is FileSource) { return id == other.id; } else if (other is Source) { return uri == other.uri; } return false; } @override bool exists() => file.exists; @override String toString() { return file.path; } }