diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..1b65ede --- /dev/null +++ b/.env.example @@ -0,0 +1,6 @@ +APP_VERSION=2.1.7 +GITHUB_REPOSITORY_URL=https://github.com/techouse/alfred-tailwindcss-docs +SUPPORTED_VERSIONS=v0,v1,v2,v3 +ALGOLIA_SEARCH_INDEX= +ALGOLIA_APPLICATION_ID= +ALGOLIA_SEARCH_ONLY_API_KEY= diff --git a/.gitignore b/.gitignore index 124e4c7..60c0aea 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ build/ # macOS specific .DS_Store -bin/query_cache/ -bin/update_cache/ +bin/*_cache/ sign.sh + +.env diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3755ff1 --- /dev/null +++ b/Makefile @@ -0,0 +1,54 @@ +# Makefile + +help: + @printf "%-20s %s\n" "Target" "Description" + @printf "%-20s %s\n" "------" "-----------" + @make -pqR : 2>/dev/null \ + | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' \ + | sort \ + | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' \ + | xargs -I _ sh -c 'printf "%-20s " _; make _ -nB | (grep -i "^# Help:" || echo "") | tail -1 | sed "s/^# Help: //g"' + +analyze: + @# Help: Analyze the project's Dart code. + dart analyze --fatal-infos + +compile: + @# Help: Compile the executable binary + bash ./build.sh + +check_format: + @# Help: Check the formatting of one or more Dart files. + dart format --output=none --set-exit-if-changed . + +check_outdated: + @# Help: Check which of the project's packages are outdated. + dart pub outdated + +check_style: + @# Help: Analyze the project's Dart code and check the formatting one or more Dart files. + make analyze && make check_format + +code_gen: + @# Help: Run the build system for Dart code generation and modular compilation. + dart run build_runner build --delete-conflicting-outputs + +code_gen_watcher: + @# Help: Run the build system for Dart code generation and modular compilation as a watcher. + dart run build_runner watch --delete-conflicting-outputs + +format: + @# Help: Format one or more Dart files. + dart format . + +install: + @# Help: Install all the project's packages + dart pub get + +sure: + @# Help: Analyze the project's Dart code, check the formatting one or more Dart files and run unit tests for the current project. + make check_style && make tests + +upgrade: + @# Help: Upgrade all the project's packages. + dart pub upgrade diff --git a/bin/main.dart b/bin/main.dart index b03aefa..6b4584c 100644 --- a/bin/main.dart +++ b/bin/main.dart @@ -13,26 +13,20 @@ import 'package:args/args.dart' show ArgParser, ArgResults; import 'package:collection/collection.dart' show IterableExtension; import 'package:html_unescape/html_unescape.dart' show HtmlUnescape; -import 'src/constants/config.dart' show Config; +import 'src/env/env.dart' show Env; import 'src/models/search_result.dart' show SearchResult; import 'src/services/algolia_search.dart' show AlgoliaSearch; -final HtmlUnescape unescape = HtmlUnescape(); +part 'main_helpers.dart'; -final AlfredWorkflow workflow = AlfredWorkflow(); -final AlfredUpdater updater = AlfredUpdater( - githubRepositoryUrl: Config.githubRepositoryUrl, - currentVersion: Config.version, - updateInterval: Duration(days: 7), -); -bool verbose = false; -bool update = false; +bool _verbose = false; +bool _update = false; void main(List arguments) async { try { exitCode = 0; - workflow.clearItems(); + _workflow.clearItems(); final ArgParser parser = ArgParser() ..addOption('query', abbr: 'q', defaultsTo: '') @@ -40,122 +34,50 @@ void main(List arguments) async { ..addFlag('update', abbr: 'u', defaultsTo: false); final ArgResults args = parser.parse(arguments); - update = args['update']; - if (update) { + _update = args['update']; + if (_update) { stdout.writeln('Updating workflow...'); - return await updater.update(); + return await _updater.update(); } - verbose = args['verbose']; + _verbose = args['verbose']; List query = args['query'].replaceAll(RegExp(r'\s+'), ' ').trim().split(' '); String? version = - query.firstWhereOrNull((el) => Config.supportedVersions.contains(el)); + query.firstWhereOrNull((el) => Env.supportedVersions.contains(el)); if (version != null) { query.removeWhere((str) => str == version); } else { - version = Config.supportedVersions.last; + version = Env.supportedVersions.last; } final String queryString = query.join(' ').trim().toLowerCase(); - if (verbose) stdout.writeln('Query: "$queryString"'); + if (_verbose) stdout.writeln('Query: "$queryString"'); if (queryString.isEmpty) { _showPlaceholder(); } else { - workflow.cacheKey = '${queryString}_$version'; - if (await workflow.getItems() == null) { + _workflow.cacheKey = '${queryString}_$version'; + if (await _workflow.getItems() == null) { await _performSearch(queryString, version: version); } } } on FormatException catch (err) { exitCode = 2; - workflow.addItem(AlfredItem(title: err.toString())); + _workflow.addItem(AlfredItem(title: err.toString())); } catch (err) { exitCode = 1; - workflow.addItem(AlfredItem(title: err.toString())); - if (verbose) rethrow; + _workflow.addItem(AlfredItem(title: err.toString())); + if (_verbose) rethrow; } finally { - if (!update) { - if (await updater.updateAvailable()) { - workflow.run(addToBeginning: updateItem); + if (!_update) { + if (await _updater.updateAvailable()) { + _workflow.run(addToBeginning: updateItem); } else { - workflow.run(); + _workflow.run(); } } } } - -const updateItem = AlfredItem( - title: 'Auto-Update available!', - subtitle: 'Press to auto-update to a new version of this workflow.', - arg: 'update:workflow', - match: - 'Auto-Update available! Press to auto-update to a new version of this workflow.', - icon: AlfredItemIcon(path: 'alfredhatcog.png'), - valid: true, -); - -void _showPlaceholder() { - workflow.addItem( - const AlfredItem( - title: 'Search the Tailwind CSS docs...', - icon: AlfredItemIcon(path: 'icon.png'), - ), - ); -} - -Future _performSearch(String query, {String? version}) async { - final AlgoliaQuerySnapshot snapshot = await AlgoliaSearch.query( - query, - version: version, - ); - - if (snapshot.nbHits > 0) { - final AlfredItems items = AlfredItems( - snapshot.hits - .map((snapshot) => SearchResult.fromJson(snapshot.data)) - .map((result) { - final int level = int.tryParse(result.type.substring(3)) ?? 0; - final String? title = result.hierarchy.getLevel(level); - final Map hierarchy = result.hierarchy.toJson() - ..removeWhere((_, value) => value == null); - - return AlfredItem( - uid: result.objectID, - title: title!, - subtitle: - level > 0 ? unescape.convert(hierarchy.values.join(' > ')) : null, - arg: result.url, - text: AlfredItemText( - largeType: title, - copy: result.url, - ), - quickLookUrl: result.url, - icon: AlfredItemIcon(path: 'icon.png'), - valid: true, - ); - }).toList(), - ); - workflow.addItems(items.items); - } else { - final Uri url = - Uri.https('www.google.com', '/search', {'q': 'Tailwind CSS $query'}); - - workflow.addItem( - AlfredItem( - title: 'No matching answers found', - subtitle: 'Shall I try and search Google?', - arg: url.toString(), - text: AlfredItemText( - copy: url.toString(), - ), - quickLookUrl: url.toString(), - icon: AlfredItemIcon(path: 'google.png'), - valid: true, - ), - ); - } -} diff --git a/bin/main_helpers.dart b/bin/main_helpers.dart new file mode 100644 index 0000000..4dc90a6 --- /dev/null +++ b/bin/main_helpers.dart @@ -0,0 +1,84 @@ +part of 'main.dart'; + +final HtmlUnescape _unescape = HtmlUnescape(); + +final AlfredWorkflow _workflow = AlfredWorkflow(); + +final AlfredUpdater _updater = AlfredUpdater( + githubRepositoryUrl: Uri.parse(Env.githubRepositoryUrl), + currentVersion: Env.appVersion, + updateInterval: Duration(days: 7), +); + +const updateItem = AlfredItem( + title: 'Auto-Update available!', + subtitle: 'Press to auto-update to a new version of this workflow.', + arg: 'update:workflow', + match: + 'Auto-Update available! Press to auto-update to a new version of this workflow.', + icon: AlfredItemIcon(path: 'alfredhatcog.png'), + valid: true, +); + +void _showPlaceholder() { + _workflow.addItem( + const AlfredItem( + title: 'Search the Tailwind CSS docs...', + icon: AlfredItemIcon(path: 'icon.png'), + ), + ); +} + +Future _performSearch(String query, {String? version}) async { + final AlgoliaQuerySnapshot snapshot = await AlgoliaSearch.query( + query, + version: version, + ); + + if (snapshot.nbHits > 0) { + final AlfredItems items = AlfredItems( + snapshot.hits + .map((snapshot) => SearchResult.fromJson(snapshot.data)) + .map((result) { + final int level = int.tryParse(result.type.substring(3)) ?? 0; + final String? title = result.hierarchy.getLevel(level); + final Map hierarchy = result.hierarchy.toJson() + ..removeWhere((_, value) => value == null); + + return AlfredItem( + uid: result.objectID, + title: title!, + subtitle: level > 0 + ? _unescape.convert(hierarchy.values.join(' > ')) + : null, + arg: result.url, + text: AlfredItemText( + largeType: title, + copy: result.url, + ), + quickLookUrl: result.url, + icon: AlfredItemIcon(path: 'icon.png'), + valid: true, + ); + }).toList(), + ); + _workflow.addItems(items.items); + } else { + final Uri url = + Uri.https('www.google.com', '/search', {'q': 'Tailwind CSS $query'}); + + _workflow.addItem( + AlfredItem( + title: 'No matching answers found', + subtitle: 'Shall I try and search Google?', + arg: url.toString(), + text: AlfredItemText( + copy: url.toString(), + ), + quickLookUrl: url.toString(), + icon: AlfredItemIcon(path: 'google.png'), + valid: true, + ), + ); + } +} diff --git a/bin/src/constants/config.dart b/bin/src/constants/config.dart deleted file mode 100644 index d8eba52..0000000 --- a/bin/src/constants/config.dart +++ /dev/null @@ -1,12 +0,0 @@ -class Config { - Config._(); - - static const String version = '2.1.6'; - static final Uri githubRepositoryUrl = - Uri.https('github.com', '/techouse/alfred-tailwindcss-docs'); - static const String algoliaApplicationId = 'KNPXZI5B0M'; - static const String algoliaSearchOnlyApiKey = - '5fc87cef58bb80203d2207578309fab6'; - static const String algoliaSearchIndex = 'tailwindcss'; - static const List supportedVersions = ['v0', 'v1', 'v2', 'v3']; -} diff --git a/bin/src/env/.gitignore b/bin/src/env/.gitignore new file mode 100644 index 0000000..ae390e0 --- /dev/null +++ b/bin/src/env/.gitignore @@ -0,0 +1,2 @@ +*.g.dart +!.gitignore \ No newline at end of file diff --git a/bin/src/env/env.dart b/bin/src/env/env.dart new file mode 100644 index 0000000..823cfe1 --- /dev/null +++ b/bin/src/env/env.dart @@ -0,0 +1,26 @@ +import 'package:envied/envied.dart'; + +part 'env.g.dart'; + +@Envied(path: '.env') +abstract class Env { + @EnviedField(varName: 'APP_VERSION') + static const String appVersion = _Env.appVersion; + + @EnviedField(varName: 'GITHUB_REPOSITORY_URL') + static const String githubRepositoryUrl = _Env.githubRepositoryUrl; + + @EnviedField(varName: 'ALGOLIA_APPLICATION_ID', obfuscate: true) + static final String algoliaApplicationId = _Env.algoliaApplicationId; + + @EnviedField(varName: 'ALGOLIA_SEARCH_ONLY_API_KEY', obfuscate: true) + static final String algoliaSearchOnlyApiKey = _Env.algoliaSearchOnlyApiKey; + + @EnviedField(varName: 'ALGOLIA_SEARCH_INDEX', obfuscate: true) + static final String algoliaSearchIndex = _Env.algoliaSearchIndex; + + @EnviedField(varName: 'SUPPORTED_VERSIONS') + static const String _supportedVersions = _Env._supportedVersions; + + static final List supportedVersions = _supportedVersions.split(','); +} diff --git a/bin/src/services/algolia_search.dart b/bin/src/services/algolia_search.dart index 4f76f29..5b6e25e 100644 --- a/bin/src/services/algolia_search.dart +++ b/bin/src/services/algolia_search.dart @@ -1,15 +1,15 @@ import 'package:algolia/algolia.dart' show Algolia, AlgoliaQuery, AlgoliaQuerySnapshot; -import '../constants/config.dart'; +import '../env/env.dart'; import '../models/search_result.dart'; class AlgoliaSearch { AlgoliaSearch._(); static final Algolia _algolia = Algolia.init( - applicationId: Config.algoliaApplicationId, - apiKey: Config.algoliaSearchOnlyApiKey, + applicationId: Env.algoliaApplicationId, + apiKey: Env.algoliaSearchOnlyApiKey, ); static Future query( @@ -17,9 +17,9 @@ class AlgoliaSearch { String? version, }) async { final AlgoliaQuery query = _algolia.instance - .index(Config.algoliaSearchIndex) + .index(Env.algoliaSearchIndex) .query(queryString) - .facetFilter('version:${version ?? Config.supportedVersions.last}') + .facetFilter('version:${version ?? Env.supportedVersions.last}') .setAttributesToRetrieve(SearchResult.attributesToRetrieve) .setAttributesToSnippet(SearchResult.attributesToSnippet) .setSnippetEllipsisText(SearchResult.snippetEllipsisText) diff --git a/info.plist b/info.plist index a473479..d199cff 100644 --- a/info.plist +++ b/info.plist @@ -215,7 +215,7 @@ variablesdontexport version - 2.1.6 + 2.1.7 webaddress https://github.com/techouse diff --git a/pubspec.lock b/pubspec.lock index 2607374..7e7d8e9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,14 +7,14 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "46.0.0" + version: "47.0.0" alfred_workflow: dependency: "direct main" description: name: alfred_workflow url: "https://pub.dartlang.org" source: hosted - version: "0.2.3" + version: "0.2.8" algolia: dependency: "direct main" description: @@ -28,7 +28,7 @@ packages: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "4.6.0" + version: "4.7.0" analyzer_plugin: dependency: transitive description: @@ -56,21 +56,28 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.9.0" + version: "2.10.0" + autoequal: + dependency: transitive + description: + name: autoequal + url: "https://pub.dartlang.org" + source: hosted + version: "0.5.1" build: dependency: transitive description: name: build url: "https://pub.dartlang.org" source: hosted - version: "2.3.0" + version: "2.3.1" build_config: dependency: transitive description: name: build_config url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" build_daemon: dependency: transitive description: @@ -84,21 +91,21 @@ packages: name: build_resolvers url: "https://pub.dartlang.org" source: hosted - version: "2.0.9" + version: "2.0.10" build_runner: dependency: "direct dev" description: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "2.2.0" + version: "2.3.2" build_runner_core: dependency: transitive description: name: build_runner_core url: "https://pub.dartlang.org" source: hosted - version: "7.2.3" + version: "7.2.7" built_collection: dependency: transitive description: @@ -112,7 +119,7 @@ packages: name: built_value url: "https://pub.dartlang.org" source: hosted - version: "8.4.1" + version: "8.4.2" checked_yaml: dependency: transitive description: @@ -133,28 +140,28 @@ packages: name: code_builder url: "https://pub.dartlang.org" source: hosted - version: "4.2.0" + version: "4.3.0" collection: dependency: "direct main" description: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.16.0" + version: "1.17.0" convert: dependency: transitive description: name: convert url: "https://pub.dartlang.org" source: hosted - version: "3.0.2" + version: "3.1.1" copy_with_extension: dependency: transitive description: name: copy_with_extension url: "https://pub.dartlang.org" source: hosted - version: "4.0.3" + version: "4.0.4" crypto: dependency: transitive description: @@ -175,14 +182,35 @@ packages: name: dart_code_metrics url: "https://pub.dartlang.org" source: hosted - version: "4.17.1" + version: "4.19.2" dart_style: dependency: transitive description: name: dart_style url: "https://pub.dartlang.org" source: hosted - version: "2.2.3" + version: "2.2.4" + dotenv: + dependency: transitive + description: + name: dotenv + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.1" + envied: + dependency: "direct main" + description: + name: envied + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.3" + envied_generator: + dependency: "direct dev" + description: + name: envied_generator + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.3" equatable: dependency: transitive description: @@ -210,7 +238,7 @@ packages: name: frontend_server_client url: "https://pub.dartlang.org" source: hosted - version: "2.1.3" + version: "3.1.0" glob: dependency: transitive description: @@ -224,14 +252,14 @@ packages: name: graphs url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.2.0" html: dependency: transitive description: name: html url: "https://pub.dartlang.org" source: hosted - version: "0.15.0" + version: "0.15.1" html_unescape: dependency: "direct main" description: @@ -259,7 +287,7 @@ packages: name: http_parser url: "https://pub.dartlang.org" source: hosted - version: "4.0.1" + version: "4.0.2" io: dependency: transitive description: @@ -273,42 +301,42 @@ packages: name: js url: "https://pub.dartlang.org" source: hosted - version: "0.6.4" + version: "0.6.5" json_annotation: dependency: "direct main" description: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "4.6.0" + version: "4.7.0" json_serializable: dependency: "direct dev" description: name: json_serializable url: "https://pub.dartlang.org" source: hosted - version: "6.3.1" + version: "6.5.4" lints: dependency: "direct dev" description: name: lints url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.0.1" logging: dependency: transitive description: name: logging url: "https://pub.dartlang.org" source: hosted - version: "1.0.2" + version: "1.1.0" matcher: dependency: transitive description: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.12" + version: "0.12.13" meta: dependency: transitive description: @@ -343,7 +371,7 @@ packages: name: petitparser url: "https://pub.dartlang.org" source: hosted - version: "5.0.0" + version: "5.1.0" pool: dependency: transitive description: @@ -357,7 +385,7 @@ packages: name: pub_semver url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "2.1.2" pubspec_parse: dependency: transitive description: @@ -371,28 +399,28 @@ packages: name: shelf url: "https://pub.dartlang.org" source: hosted - version: "1.3.2" + version: "1.4.0" shelf_web_socket: dependency: transitive description: name: shelf_web_socket url: "https://pub.dartlang.org" source: hosted - version: "1.0.2" + version: "1.0.3" source_gen: dependency: transitive description: name: source_gen url: "https://pub.dartlang.org" source: hosted - version: "1.2.2" + version: "1.2.6" source_helper: dependency: transitive description: name: source_helper url: "https://pub.dartlang.org" source: hosted - version: "1.3.2" + version: "1.3.3" source_span: dependency: transitive description: @@ -406,42 +434,42 @@ packages: name: stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.10.0" + version: "1.11.0" stash: dependency: transitive description: name: stash url: "https://pub.dartlang.org" source: hosted - version: "4.3.2" + version: "4.3.4" stash_file: dependency: transitive description: name: stash_file url: "https://pub.dartlang.org" source: hosted - version: "4.3.2" + version: "4.3.4" stream_channel: dependency: transitive description: name: stream_channel url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.1" stream_transform: dependency: transitive description: name: stream_transform url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.1" + version: "1.2.0" term_glyph: dependency: transitive description: @@ -483,7 +511,7 @@ packages: name: watcher url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "1.0.2" web_socket_channel: dependency: transitive description: @@ -497,7 +525,7 @@ packages: name: xml url: "https://pub.dartlang.org" source: hosted - version: "6.1.0" + version: "6.2.0" yaml: dependency: transitive description: @@ -506,4 +534,4 @@ packages: source: hosted version: "3.1.1" sdks: - dart: ">=2.17.0 <3.0.0" + dart: ">=2.18.0 <3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 882ca1d..02831c1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,7 +4,7 @@ description: Search the Tailwind CSS documentation using Alfred # Prevent accidental publishing to pub.dev. publish_to: 'none' -version: 2.1.6 +version: 2.1.7 environment: sdk: '>=2.17.0 <3.0.0' @@ -12,6 +12,7 @@ environment: dependencies: algolia: ^1.1.1 args: ^2.3.0 + envied: ^0.2.3 html_unescape: ^2.0.0 alfred_workflow: ^0.2.0 collection: ^1.16.0 @@ -20,6 +21,7 @@ dependencies: dev_dependencies: build_runner: ^2.1.7 dart_code_metrics: ^4.8.1 + envied_generator: ^0.2.3 json_serializable: ^6.1.5 lints: ^2.0.0 diff --git a/version b/version index b6da512..9671f9a 100644 --- a/version +++ b/version @@ -1 +1 @@ -2.1.6 \ No newline at end of file +2.1.7 \ No newline at end of file