diff --git a/pkgs/cli_config/CHANGELOG.md b/pkgs/cli_config/CHANGELOG.md index a0712a79e..687d9d92d 100644 --- a/pkgs/cli_config/CHANGELOG.md +++ b/pkgs/cli_config/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.1.1 + +- Support non-String map keys in YAML configuration files. +- Support null values in YAML configuration files. + ## 0.1.0 - Initial version. diff --git a/pkgs/cli_config/lib/src/config.dart b/pkgs/cli_config/lib/src/config.dart index 25b4c23b8..6c7278f96 100644 --- a/pkgs/cli_config/lib/src/config.dart +++ b/pkgs/cli_config/lib/src/config.dart @@ -103,7 +103,7 @@ class Config { Uri? fileSourceUri, }) { // Parse config file. - final fileConfig = FileParser().parseMap(fileParsed); + final fileConfig = FileParser().parseToplevelMap(fileParsed); // Parse CLI argument defines. final cliConfig = DefinesParser().parse(commandLineDefines); diff --git a/pkgs/cli_config/lib/src/file_parser.dart b/pkgs/cli_config/lib/src/file_parser.dart index 3d54b585c..fcb1fa968 100644 --- a/pkgs/cli_config/lib/src/file_parser.dart +++ b/pkgs/cli_config/lib/src/file_parser.dart @@ -5,7 +5,7 @@ import 'package:yaml/yaml.dart'; class FileParser { - Map parse( + Map parse( String fileContents, { Uri? sourceUrl, }) { @@ -16,24 +16,25 @@ class FileParser { if (parsedYaml is! Map) { throw FormatException('YAML config must be set of key value pairs.'); } - return parseMap(parsedYaml); + return parseToplevelMap(parsedYaml); } - Map parseMap(Map input) => { - for (final entry in input.entries) - parseKey(entry.key as String): parseValue(entry.value as Object), - }; - - Object parseValue(Object value) { - if (value is Map) { - return parseMap(value); + Map parseToplevelMap(Map input) { + final result = {}; + for (final entry in input.entries) { + final key = parseToplevelKey(entry.key); + final value = entry.value as Object?; + result[key] = value; } - return value; + return result; } static final _keyRegex = RegExp('([a-z-_]+)'); - String parseKey(String key) { + String parseToplevelKey(Object? key) { + if (key is! String) { + throw FormatException("Key '$key' is not a String."); + } final match = _keyRegex.matchAsPrefix(key); if (match == null || match.group(0) != key) { throw FormatException("Define '$key' does not match expected pattern " diff --git a/pkgs/cli_config/pubspec.yaml b/pkgs/cli_config/pubspec.yaml index a3e5cb09f..ef6ffe4a7 100644 --- a/pkgs/cli_config/pubspec.yaml +++ b/pkgs/cli_config/pubspec.yaml @@ -1,6 +1,6 @@ name: cli_config description: A library to take config values from configuration files, CLI arguments, and environment variables. -version: 0.1.0 +version: 0.1.1 repository: https://github.com/dart-lang/tools/tree/main/pkgs/cli_config diff --git a/pkgs/cli_config/test/cli_config_test.dart b/pkgs/cli_config/test/cli_config_test.dart index fc8b172ba..034c2fedf 100644 --- a/pkgs/cli_config/test/cli_config_test.dart +++ b/pkgs/cli_config/test/cli_config_test.dart @@ -371,11 +371,20 @@ void main() { expect(() => Config.fromConfigFileContents(fileContents: "['asdf']"), throwsFormatException); expect( - () => Config.fromConfigFileContents(fileContents: '''foo: - bar: - WRONGKEY: - 1 -'''), + () => Config.fromConfigFileContents( + fileContents: ''' +WRONGKEY: + 1 +''' + .trim()), + throwsFormatException, + ); + expect( + () => Config.fromConfigFileContents( + fileContents: ''' +1: 'asdf' +''' + .trim()), throwsFormatException, ); }); @@ -504,4 +513,46 @@ void main() { expect(config.pathList('my_list'), []); } }); + + test('non-string key maps', () { + // This is valid in YAML (not in JSON). + // + // Such values cannot be accessed with our hierarchical keys, but they can + // be accessed with [Config.valueOf]. + final config = Config( + fileParsed: { + 'my_non_string_key_map': { + 1: 'asdf', + 2: 'foo', + }, + }, + ); + + expect( + config.valueOf>('my_non_string_key_map'), + { + 1: 'asdf', + 2: 'foo', + }, + ); + }); + + test('null values in maps', () { + final config = Config( + fileParsed: { + 'my_non_string_key_map': { + 'x': null, + 'y': 42, + }, + }, + ); + + expect( + config.valueOf>('my_non_string_key_map'), + { + 'x': null, + 'y': 42, + }, + ); + }); }