Introduce applicationConfigHome (#66)

* Introduce applicationConfigHome
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c546fd4..871b010 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 0.3.4
+
+- Introduce `applicationConfigHome` for making it easy to consistently find the
+  user-specific application configuration folder.
+
 ## 0.3.3
 
 - Reverted `meta` constraint to `^1.3.0`.
diff --git a/lib/cli_util.dart b/lib/cli_util.dart
index 0cc408d..0fdd211 100644
--- a/lib/cli_util.dart
+++ b/lib/cli_util.dart
@@ -59,3 +59,66 @@
 
 /// Return the path to the current Dart SDK.
 String getSdkPath() => path.dirname(path.dirname(Platform.resolvedExecutable));
+
+/// Get the user-specific application configuration folder for the current
+/// platform.
+///
+/// This is a location appropriate for storing application specific
+/// configuration for the current user. The [productName] should be unique to
+/// avoid clashes with other applications on the same machine. This method won't
+/// actually create the folder, merely return the recommended location for
+/// storing user-specific application configuration.
+///
+/// The folder location depends on the platform:
+///  * `%APPDATA%\<productName>` on **Windows**,
+///  * `$HOME/Library/Application Support/<productName>` on **Mac OS**,
+///  * `$XDG_CONFIG_HOME/<productName>` on **Linux**
+///     (if `$XDG_CONFIG_HOME` is defined), and,
+///  * `$HOME/.config/<productName>` otherwise.
+///
+/// This aims follows best practices for each platform, honoring the
+/// [XDG Base Directory Specification][1] on Linux and [File System Basics][2]
+/// on Mac OS.
+///
+/// Throws if `%APPDATA%` or `$HOME` is undefined.
+///
+/// [1]: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
+/// [2]: https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html#//apple_ref/doc/uid/TP40010672-CH2-SW1
+String applicationConfigHome(String productName) =>
+    path.join(_configHome, productName);
+
+String get _configHome {
+  if (Platform.isWindows) {
+    final appdata = Platform.environment['APPDATA'];
+    if (appdata == null) {
+      throw StateError('Environment variable %APPDATA% is not defined!');
+    }
+    return appdata;
+  }
+
+  if (Platform.isMacOS) {
+    return path.join(_home, 'Library', 'Application Support');
+  }
+
+  if (Platform.isLinux) {
+    final xdgConfigHome = Platform.environment['XDG_CONFIG_HOME'];
+    if (xdgConfigHome != null) {
+      return xdgConfigHome;
+    }
+    // XDG Base Directory Specification says to use $HOME/.config/ when
+    // $XDG_CONFIG_HOME isn't defined.
+    return path.join(_home, '.config');
+  }
+
+  // We have no guidelines, perhaps we should just do: $HOME/.config/
+  // same as XDG specification would specify as fallback.
+  return path.join(_home, '.config');
+}
+
+String get _home {
+  final home = Platform.environment['HOME'];
+  if (home == null) {
+    throw StateError('Environment variable \$HOME is not defined!');
+  }
+  return home;
+}
diff --git a/pubspec.yaml b/pubspec.yaml
index a5ab878..7efbd13 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: cli_util
-version: 0.3.3
+version: 0.3.4
 description: A library to help in building Dart command-line apps.
 repository: https://github.com/dart-lang/cli_util
 
diff --git a/test/cli_util_test.dart b/test/cli_util_test.dart
index 2c2c770..95ba0fb 100644
--- a/test/cli_util_test.dart
+++ b/test/cli_util_test.dart
@@ -36,4 +36,10 @@
       expect(isSdkDir(Directory(getSdkPath())), true);
     });
   });
+
+  group('applicationConfigHome', () {
+    test('returns a string', () {
+      expect(applicationConfigHome('dart'), isA<String>());
+    });
+  });
 }