Skip to content

Commit

Permalink
Merge pull request #52 from kekavc24/fix/ensure-counter-strictness
Browse files Browse the repository at this point in the history
fix: ensure counter strictness
  • Loading branch information
kekavc24 authored Mar 15, 2024
2 parents 3b0f80f + 0de12ca commit 808a482
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 36 deletions.
29 changes: 11 additions & 18 deletions lib/src/core/yaml_transformers/data/matched_node_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@ part of '../yaml_transformer.dart';

/// Data object specifically created when a `Finder` finds it based on some
/// predefined condition
@immutable
class MatchedNodeData extends NodeData {
const MatchedNodeData(
super.precedingKeys,
super.key,
super.value,
class MatchedNodeData {
MatchedNodeData(
this.node,
this.matchedKeys,
this.matchedValue,
this.matchedPairs,
Expand All @@ -21,20 +18,21 @@ class MatchedNodeData extends NodeData {
required Map<String, String> matchedPairs,
}) {
return MatchedNodeData(
nodeData.precedingKeys,
nodeData.key,
nodeData.value,
nodeData,
matchedKeys,
matchedValue,
matchedPairs,
);
}

/// Denotes [NodeData] belonging to an indexed node that has been matched
final NodeData node;

/// List of keys in [ NodeData ] path that matched any preset conditions
final List<String> matchedKeys;

/// First/Only value matched from any of the values provided
final String matchedValue;
String matchedValue;

/// Map of pairs that matched any pairs provided
final Map<String, String> matchedPairs;
Expand All @@ -48,11 +46,11 @@ class MatchedNodeData extends NodeData {

/// Get list of keys upto the last renameable key
Iterable<Key> getUptoLastRenameable() {
final keys = super.getKeysAsString();
final keys = node.getKeysAsString();
final lastIndex = matchedKeys.map(keys.lastIndexOf).max;

// Keys to be taken, include last index plus one
return super.getKeys().take(lastIndex + 1);
return node.getKeys().take(lastIndex + 1);
}

/// Get path of keys upto the last renameable key
Expand All @@ -61,10 +59,5 @@ class MatchedNodeData extends NodeData {
}

@override
List<Object> get props => [
...super.props,
matchedKeys,
matchedPairs,
matchedValue,
];
String toString() => node.toString();
}
48 changes: 41 additions & 7 deletions lib/src/core/yaml_transformers/finders/custom_tracker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ part of 'finder.dart';
///
/// See [Counter].
final class MatchCounter extends CounterWithHistory<int, dynamic, dynamic> {
MatchCounter({required int? limit}) : _limit = limit;
MatchCounter({this.limit}) : isStrict = limit != null;

final int? _limit;
final bool isStrict;

final int? limit;

/// Increments from [ MatchedNodeData ].
///
Expand All @@ -17,26 +19,58 @@ final class MatchCounter extends CounterWithHistory<int, dynamic, dynamic> {
bool incrementUsingMatch(MatchedNodeData data) {
// Add any matched keys
if (data.matchedKeys.isNotEmpty) {
increment(data.matchedKeys, origin: Origin.key);
final ignoredKeys = increment(data.matchedKeys, origin: Origin.key);

data.matchedKeys.removeWhere(ignoredKeys.contains); // Remove ignored keys
}

// Add matched value if not empty
if (data.matchedValue.isNotEmpty) {
increment([data.matchedValue], origin: Origin.value);
if (increment([data.matchedValue], origin: Origin.value).isNotEmpty) {
data.matchedValue = ''; // Remove value
}
}

// Add all pairs
if (data.matchedPairs.isNotEmpty) {
increment(data.matchedPairs.entries, origin: Origin.pair);
final ignoredPairs = increment(
data.matchedPairs.entries,
origin: Origin.pair,
) as List<MapEntry<String, String>>;

data.matchedPairs.removeWhere(
(key, value) => ignoredPairs.any(
(element) => element.key == key && element.value == value,
),
);
}

/// All must be equal or greater than limit. Other keys may have
/// been found before more than once.
///
/// Get set of all counts and check if any is below limit
final anyBelowLimit = _limit == null ||
super.trackerState.values.toSet().any((element) => element < _limit!);
final anyBelowLimit = limit == null ||
super.trackerState.values.toSet().any((element) => element < limit!);

return !anyBelowLimit;
}

@override
List<dynamic> increment(Iterable<dynamic> values, {required Origin origin}) {
final ignored = <dynamic>[];
final valuesToAdd = <dynamic>[...values];

// In strict mode, ensure we only add those below limit
if (isStrict) {
for (final value in values) {
if (getCount(value, origin: origin) == limit) {
ignored.add(value);
valuesToAdd.remove(value);
}
}
}

super.increment(valuesToAdd, origin: origin);
return ignored;
}
}
21 changes: 15 additions & 6 deletions lib/src/core/yaml_transformers/finders/finder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,8 @@ abstract base class Finder {

yield* findAllSync(prefilledCounter: true).takeWhile(
(value) {
/// Last value may be ignored. Last value itself causes the limit
/// to be reached. The limit is never reaches before.
/// Last value may be ignored. The last value itself causes the limit
/// to be reached.
if (value.reachedLimit) lastValue = value;
return !value.reachedLimit;
},
Expand All @@ -150,19 +150,28 @@ abstract base class Finder {
Iterable<FinderOutput> findAllSync({bool prefilledCounter = false}) sync* {
/// Incase this method is called indirectly via [Finder.find]
///
/// [Finder.findByCount] always prefills the counter thus always
/// sets up the [MatchCounter]
/// [Finder.findByCount] always prefills the counter and sets up the
/// [MatchCounter]
if (!prefilledCounter) _setUpCounter(null);

for (final nodeData in _generator) {
// Generate matched node data
final matchedNodeData = generateMatch(nodeData);

// We only yield it if it is valid
/// Try increment with the counter first.
///
/// The counter checks to make sure this [MatchedNodeData] has valid
/// matches. Matches below the limit. The [MatchedNodeData] will be
/// modified any redudant matches dropped.
///
/// Nothing happens if below the limit
final reachedLimit = counter!.incrementUsingMatch(matchedNodeData);

// If still valid after any modification, yield!
if (matchedNodeData.isValidMatch()) {
yield (
data: matchedNodeData,
reachedLimit: counter!.incrementUsingMatch(matchedNodeData),
reachedLimit: reachedLimit,
);
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/src/core/yaml_transformers/replacers/replacer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ abstract class Replacer {

// Just return the value instead as a string
return _getReplacementCandidate(
matchedNodeData.data,
matchedNodeData.node.data,
useFirst: useFirst,
) as T;
}
Expand Down
8 changes: 4 additions & 4 deletions lib/src/core/yaml_transformers/replacers/value_replacer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ class ValueReplacer extends Replacer {

final updatedMap = modifiable.updateIndexedMap(
replacement,
target: matchedNodeData.key,
path: matchedNodeData.precedingKeys,
target: matchedNodeData.node.key,
path: matchedNodeData.node.precedingKeys,
keyAndReplacement: {},
value: matchedNodeData.value,
value: matchedNodeData.node.value,
);

return (
mapping: {matchedNodeData.data: replacement},
mapping: {matchedNodeData.node.data: replacement},
updatedMap: YamlMap.wrap(updatedMap),
);
}
Expand Down

0 comments on commit 808a482

Please sign in to comment.