Skip to content

Commit

Permalink
eng(build): DRY recycled code to brick_build and brick_core (#419)
Browse files Browse the repository at this point in the history
  • Loading branch information
tshedor authored Aug 27, 2024
1 parent aaa2584 commit 68c5a71
Show file tree
Hide file tree
Showing 56 changed files with 531 additions and 518 deletions.
6 changes: 6 additions & 0 deletions packages/brick_build/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
## Unreleased

## 3.2.0

- Add convenience mixin `AnnotationFinderWithFieldRename` for field renames in generators
- Add `SharedChecker#withoutNullResultType` for retrieving the final typed version of a field. "withoutNull" was used instead of the more idiomatic "non-null" because non-null in the Dart ecosystem and lower-level analyzer means "not null-safe." This method strips null suffixes and type symbols like `<` and `>`.
- **BREAKING CHANGE** Remove `StringHelpers.kebabCase` and `StringHelpers.pascalCase`. These should be invoked from the `AnnotationFinderWithFieldRename#renameField` method.

## 3.1.0

- Apply standardized lints
Expand Down
4 changes: 3 additions & 1 deletion packages/brick_build/example/file_serialize.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'package:brick_build/generators.dart';

import 'file_serdes_generator.dart';

/// Generate serialized code for each field to write to a file
Expand Down Expand Up @@ -29,7 +31,7 @@ class FileSerialize<_Model extends FileModel> extends FileSerdesGenerator<_Model

// Iterable<enum>
if (argTypeChecker.isEnum) {
return '$fieldValue?.map((e) => ${checker.argType.getDisplayString().replaceAll('?', '')}.values.indexOf(e))';
return '$fieldValue?.map((e) => ${SharedChecker.withoutNullability(checker.argType)}.values.indexOf(e))';
}

// Iterable<OfflineFirstModel>, Iterable<Future<OfflineFirstModel>>
Expand Down
1 change: 1 addition & 0 deletions packages/brick_build/lib/generators.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export 'package:brick_build/src/adapter_generator.dart';
export 'package:brick_build/src/annotation_finder.dart';
export 'package:brick_build/src/annotation_finder_with_field_rename.dart';
export 'package:brick_build/src/annotation_super_generator.dart';
export 'package:brick_build/src/model_dictionary_generator.dart';
export 'package:brick_build/src/provider_serializable_generator.dart';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import 'package:brick_build/src/annotation_finder.dart';
import 'package:brick_build/src/utils/string_helpers.dart';
import 'package:brick_core/field_rename.dart';

mixin AnnotationFinderWithFieldRename<Annotation extends Object> on AnnotationFinder<Annotation> {
/// Change serialization key based on the configuration.
/// `name` defined with a field annotation takes precedence.
String renameField(String name, FieldRename? configValue, FieldRename defaultValue) {
final renameTo = configValue ?? defaultValue;
switch (renameTo) {
case FieldRename.none:
return name;
case FieldRename.snake:
return StringHelpers.snakeCase(name);

/// Converts a camelized string to kebab-case
/// Taken from [json_serializable](https://github.com/dart-lang/json_serializable/blob/d7e6612cf947e150710007a63b439f8f0c316d42/json_serializable/lib/src/utils.dart#L38-L47)
case FieldRename.kebab:
return name.replaceAllMapped(RegExp('[A-Z]'), (match) {
var lower = match.group(0)!.toLowerCase();

if (match.start > 0) {
lower = '-$lower';
}

return lower;
});

/// Capitalizes first letter
/// Taken from [json_serializable](https://github.com/dart-lang/json_serializable/blob/d7e6612cf947e150710007a63b439f8f0c316d42/json_serializable/lib/src/utils.dart#L30-L36)
case FieldRename.pascal:
if (name.isEmpty) return '';

return name[0].toUpperCase() + name.substring(1);
}
}
}
23 changes: 22 additions & 1 deletion packages/brick_build/lib/src/utils/shared_checker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ class SharedChecker<_SiblingModel extends Model> {
throw InvalidGenerationSourceError(
'Type argument for ${targetType.getDisplayString()} is undefined.',
todo:
'Define the type on class ${targetType.element}, e.g. `extends ${classElement.supertype!.getDisplayString().replaceAll('?', '')}<int>`',
'Define the type on class ${targetType.element}, e.g. `extends ${withoutNullability(classElement.supertype!)}<int>`',
element: targetType.element,
);
}
Expand Down Expand Up @@ -221,6 +221,27 @@ class SharedChecker<_SiblingModel extends Model> {
return targetType;
}

/// Returns the final version of a type without decoration. It will not have a null suffix.
///
/// For example, `Future<String>`, `List<Future<String>>`, `String?` and `Future<String?>`
/// will all return `String`.
String get withoutNullResultType {
final typeRemover = RegExp(r'\<[,\s\w]+\>');

// Future<?>, Iterable<?>
if (isFuture || isIterable) {
final checker = SharedChecker<_SiblingModel>(argType);
return checker.withoutNullResultType;
}

if (toJsonMethod != null) {
return withoutNullability(toJsonMethod!.returnType).replaceAll(typeRemover, '');
}

// remove arg types as they can't be declared in final fields
return withoutNullability(targetType).replaceAll(typeRemover, '');
}

/// Print the `DartType` without nullability
static String withoutNullability(DartType type) => type.getDisplayString().replaceAll('?', '');

Expand Down
22 changes: 0 additions & 22 deletions packages/brick_build/lib/src/utils/string_helpers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,6 @@ class StringHelpers {
return lower;
});
}

/// Capitalizes first letter
/// Taken from [json_serializable](https://github.com/dart-lang/json_serializable/blob/d7e6612cf947e150710007a63b439f8f0c316d42/json_serializable/lib/src/utils.dart#L30-L36)
static String pascalCase(String input) {
if (input.isEmpty) return '';

return input[0].toUpperCase() + input.substring(1);
}

/// Converts a camelized string to kebab-case
/// Taken from [json_serializable](https://github.com/dart-lang/json_serializable/blob/d7e6612cf947e150710007a63b439f8f0c316d42/json_serializable/lib/src/utils.dart#L38-L47)
static String kebabCase(String input) {
return input.replaceAllMapped(RegExp('[A-Z]'), (match) {
var lower = match.group(0)!.toLowerCase();

if (match.start > 0) {
lower = '-$lower';
}

return lower;
});
}
}

// Borrowed from [JsonSerializable](https://github.com/dart-lang/json_serializable/blob/9fcee71528f17f8e9e80e90003264e84d048977b/json_serializable/lib/src/utils.dart)
Expand Down
2 changes: 1 addition & 1 deletion packages/brick_build/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ homepage: https://github.com/GetDutchie/brick/tree/main/packages/brick_build
issue_tracker: https://github.com/GetDutchie/brick/issues
repository: https://github.com/GetDutchie/brick

version: 3.1.0
version: 3.2.0

environment:
sdk: ">=2.18.0 <4.0.0"
Expand Down
52 changes: 28 additions & 24 deletions packages/brick_core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,61 +1,65 @@
## Unreleased

## 1.2.1

- Add `FieldRename` to `FieldSerializable`

## 1.2.0

* Apply standardized lints
* Upgrade minimum Dart to 2.18
- Apply standardized lints
- Upgrade minimum Dart to 2.18

## 1.1.2

* Support Dart 3
* Loosen dependency restrictions to major versions
- Support Dart 3
- Loosen dependency restrictions to major versions

## 1.1.1

* Add `subscribe` to `QueryAction`
- Add `subscribe` to `QueryAction`

## 1.1.0

* Add Dart lints
* Add `enumAsString`
- Add Dart lints
- Add `enumAsString`

## 1.0.0+1

* Null safety cleanup and refactor
- Null safety cleanup and refactor

## 1.0.0

* Null safety
* **BREAKING CHANGE**: because `required` is now a first-class Dart keyword, `required` in `WherePhrase`, `WhereCondition`, `And`, `Or`, and `Where` has been renamed to `isRequired`.
* Add optional method `Provider#exists`. Whether a model instance is present. `null` is returned when existence is unknown. The model instance is not hydrated in the function output; a `bool` variant (e.g. `List<bool>`, `Map<_Model, bool>`) should be returned.
- Null safety
- **BREAKING CHANGE**: because `required` is now a first-class Dart keyword, `required` in `WherePhrase`, `WhereCondition`, `And`, `Or`, and `Where` has been renamed to `isRequired`.
- Add optional method `Provider#exists`. Whether a model instance is present. `null` is returned when existence is unknown. The model instance is not hydrated in the function output; a `bool` variant (e.g. `List<bool>`, `Map<_Model, bool>`) should be returned.

## 0.0.6

* Add a `doesNotContain` enum to `Compare` for `Where` queries
- Add a `doesNotContain` enum to `Compare` for `Where` queries

## 0.0.5

* Rename `Query#params` to `Query#providerArgs`, reflecting the much narrower purpose of the member
- Rename `Query#params` to `Query#providerArgs`, reflecting the much narrower purpose of the member

## 0.0.4

* `FieldSerializable#defaultValue` changes from `dynamic` to `String`. As this is injected directly into the adapter, it does not need to be dynamic and should better reflect its purpose.
- `FieldSerializable#defaultValue` changes from `dynamic` to `String`. As this is injected directly into the adapter, it does not need to be dynamic and should better reflect its purpose.

## 0.0.3+1

* Moves generator placeholders to `FieldSerializable` form `OfflineFirst`
* Removes query validation that ensures all Where conditions have a non-null value
- Moves generator placeholders to `FieldSerializable` form `OfflineFirst`
- Removes query validation that ensures all Where conditions have a non-null value

## 0.0.3

* Add `And` and `Or` `Where` subclasses
* Removes Type argument from `Where`
* Adds semantic methods to `Where` such as `isExactly` and
* **BREAKING** Revise `Where` syntax. This removes the second positional argument in favor of using it in a semantic method.
* Adds `Where.exact` factory to preserve previous, short syntax
* Move query-related files to `src/query` and make them accessible from a barrel file in the lib root
- Add `And` and `Or` `Where` subclasses
- Removes Type argument from `Where`
- Adds semantic methods to `Where` such as `isExactly` and
- **BREAKING** Revise `Where` syntax. This removes the second positional argument in favor of using it in a semantic method.
- Adds `Where.exact` factory to preserve previous, short syntax
- Move query-related files to `src/query` and make them accessible from a barrel file in the lib root

## 0.0.2

* Fix linter hints
* Adds `initialize` method to `ModelRepository`. This is enforces a predictable, overridable method for sub classes
- Fix linter hints
- Adds `initialize` method to `ModelRepository`. This is enforces a predictable, overridable method for sub classes
16 changes: 16 additions & 0 deletions packages/brick_core/lib/field_rename.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/// Values for the automatic field renaming behavior for class-level serializables.
///
/// Heavily borrowed/inspired by [JsonSerializable](https://github.com/dart-lang/json_serializable/blob/a581e5cc9ee25bf4ad61e8f825a311289ade905c/json_serializable/lib/src/json_key_utils.dart#L164-L179)
enum FieldRename {
/// Leave fields unchanged
none,

/// Encodes field name from `snakeCase` to `snake_case`.
snake,

/// Encodes field name from `kebabCase` to `kebab-case`.
kebab,

/// Capitalizes first letter of field name
pascal,
}
2 changes: 1 addition & 1 deletion packages/brick_core/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ homepage: https://github.com/GetDutchie/brick/tree/main/packages/brick_core
issue_tracker: https://github.com/GetDutchie/brick/issues
repository: https://github.com/GetDutchie/brick

version: 1.2.0
version: 1.2.1

environment:
sdk: ">=2.18.0 <4.0.0"
Expand Down
Loading

0 comments on commit 68c5a71

Please sign in to comment.