blob: 89c676cf8fbee7671cdd98effd1b8e1c7bb1489f [file] [log] [blame] [edit]
// Copyright (c) 2025, 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:convert';
import 'package:json_rpc_2/json_rpc_2.dart' show RpcException;
import '../constants.dart';
import '../dart_tooling_daemon.dart';
import '../response_types/response_types.dart';
import '../rpc_error_codes.dart' show RpcErrorCodes;
extension FileSystemService on DartToolingDaemon {
/// Reads the file at [uri] from disk in the environment where the Dart
/// Tooling Daemon is running.
///
/// If [uri] is not contained in the IDE workspace roots, then an
/// [RpcException] with [RpcErrorCodes.kPermissionDenied] is thrown.
///
/// If [uri] does not exist, then an [RpcException] exception with error
/// code [RpcErrorCodes.kFileDoesNotExist] is thrown.
///
/// If [uri] does not have a file scheme, then an [RpcException] with
/// [RpcErrorCodes.kExpectsUriParamWithFileScheme] is thrown.
Future<FileContent> readFileAsString(
Uri uri, {
Encoding encoding = utf8,
}) async {
final result = await call(
FileSystemServiceConstants.serviceName,
FileSystemServiceConstants.readFileAsString,
params: {
DtdParameters.uri: uri.toString(),
DtdParameters.encoding: encoding.name,
},
);
return FileContent.fromDTDResponse(result);
}
/// Writes [contents] to the file at [uri] in the environment where the Dart
/// Tooling Daemon is running.
///
/// The file will be created if it does not exist, and it will be overwritten
/// if it already exist.
///
/// If [uri] is not contained in the IDE workspace roots, then an
/// [RpcException] with [RpcErrorCodes.kPermissionDenied] is thrown.
///
/// If [uri] does not have a file scheme, then an [RpcException] with
/// [RpcErrorCodes.kExpectsUriParamWithFileScheme] is thrown.
Future<void> writeFileAsString(
Uri uri,
String contents, {
Encoding encoding = utf8,
}) async {
await call(
FileSystemServiceConstants.serviceName,
FileSystemServiceConstants.writeFileAsString,
params: {
DtdParameters.uri: uri.toString(),
DtdParameters.contents: contents,
DtdParameters.encoding: encoding.name,
},
);
}
/// Lists the directories and files under the directory at [uri] in the
/// environment where the Dart Tooling Daemon is running.
///
/// If [uri] is not a directory, throws an [RpcException] exception with error
/// code [RpcErrorCodes.kDirectoryDoesNotExist].
///
/// If [uri] is not contained in the IDE workspace roots, then an
/// [RpcException] with [RpcErrorCodes.kPermissionDenied] is thrown.
///
/// If [uri] does not have a file scheme, then an [RpcException] with
/// [RpcErrorCodes.kExpectsUriParamWithFileScheme] is thrown.
///
/// The returned uris will be `file://` Uris.
Future<UriList> listDirectoryContents(Uri uri) async {
final result = await call(
FileSystemServiceConstants.serviceName,
FileSystemServiceConstants.listDirectoryContents,
params: {
DtdParameters.uri: uri.toString(),
},
);
return UriList.fromDTDResponse(result);
}
/// Sets the IDE workspace roots for the FileSystem service.
///
/// This is a privileged RPC that require's a [secret], which is provided by
/// the Dart Tooling Daemon, to be called successfully. This secret is
/// generated by the daemon and provided to its spawner to ensure only trusted
/// clients can set workspace roots. If [secret] is invalid, an [RpcException]
/// with error code [RpcErrorCodes.kPermissionDenied] is thrown.
///
/// If [secret] does not match the secret created when Dart Tooling Daemon was
/// created, then an [RpcException] with [RpcErrorCodes.kPermissionDenied] is
/// thrown.
///
/// If one of the [roots] is missing a "file" scheme then an [RpcException]
/// with [RpcErrorCodes.kExpectsUriParamWithFileScheme] is thrown.
Future<void> setIDEWorkspaceRoots(String secret, List<Uri> roots) async {
await call(
FileSystemServiceConstants.serviceName,
FileSystemServiceConstants.setIDEWorkspaceRoots,
params: {
DtdParameters.roots: roots.map<String>((e) => e.toString()).toList(),
DtdParameters.secret: secret,
},
);
}
/// Gets the IDE workspace roots for the FileSystem service.
///
/// The returned uris will be `file://` Uris.
Future<IDEWorkspaceRoots> getIDEWorkspaceRoots() async {
final result = await call(
FileSystemServiceConstants.serviceName,
FileSystemServiceConstants.getIDEWorkspaceRoots,
);
return IDEWorkspaceRoots.fromDTDResponse(result);
}
/// Gets the project roots contained within the current set of IDE workspace
/// roots.
///
/// A project root is any directory that contains a 'pubspec.yaml' file. If
/// IDE workspace roots are not set, or if there are no project roots within
/// the IDE workspace roots, this method will return an empty [UriList].
///
/// [depth] is the maximum depth that each IDE workspace root directory tree
/// will be searched for project roots.
///
/// The returned uris will be `file://` Uris.
Future<UriList> getProjectRoots({
int depth = defaultGetProjectRootsDepth,
}) async {
final result = await call(
FileSystemServiceConstants.serviceName,
FileSystemServiceConstants.getProjectRoots,
params: {DtdParameters.depth: depth},
);
return UriList.fromDTDResponse(result);
}
}