dew/packages/core/lib/src/config.dart
Chris Hendrickson b27b5f365d Add context.dirs.workspace getter to ProjectDirs
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-23 23:16:00 -04:00

70 lines
2.2 KiB
Dart

import 'package:file/file.dart';
import 'package:file/local.dart';
import 'package:path/path.dart' as p;
import 'package:yaml/yaml.dart';
/// Thin wrapper around the raw project YAML.
///
/// Feature packages extend this class via Dart extension methods to expose
/// typed configuration (e.g. [KanbanDewConfig.kanban], [McpDewConfig.mcp]).
/// This keeps feature-specific config classes out of core.
class DewConfig {
final YamlMap raw;
const DewConfig({required this.raw});
factory DewConfig.fromYaml(YamlMap yaml) => DewConfig(raw: yaml);
}
/// Path helper for well-known directories under a project root.
///
/// Feature packages extend this via extension methods to expose their own
/// directories (e.g. [KanbanDirs.kanban]).
class ProjectDirs {
final String _root;
const ProjectDirs(this._root);
/// The workspace root (where `.project/` lives).
String get workspace => _root;
/// `.project/` directory.
String get project => p.join(_root, '.project');
}
/// Locates the nearest project root and exposes the parsed [DewConfig].
class ProjectContext {
final String root;
final DewConfig config;
final FileSystem fs;
const ProjectContext({required this.root, required this.config, required this.fs});
/// Typed path helpers for this project's well-known directories.
ProjectDirs get dirs => ProjectDirs(root);
/// Walks up from [from] (defaults to [fs.currentDirectory]) until a
/// `.project/dew.yaml` is found.
static Future<ProjectContext> find({
FileSystem fs = const LocalFileSystem(),
Directory? from,
}) async {
var dir = from ?? fs.currentDirectory;
while (true) {
final configFile = fs.file(p.join(dir.path, '.project', 'dew.yaml'));
if (await configFile.exists()) {
final yaml = loadYaml(await configFile.readAsString()) as YamlMap;
return ProjectContext(
root: dir.path,
config: DewConfig.fromYaml(yaml),
fs: fs,
);
}
final parent = dir.parent;
if (parent.path == dir.path) {
throw StateError(
'Could not find .project/dew.yaml. '
'Run "dew init ." to initialise a project here.',
);
}
dir = parent;
}
}
}