Dartora

A, batteries‑included utility package, that was built for Dart. It provides:

  • Collections: ordered maps, multi‑view/large lists, rich iteration utilities.
  • Search: a lightweight query engine with tags, required/forbidden terms, wildcards, and scoring.
  • Math: robust rounding modes, roots/logs, comparison helpers, points/scoring types, matrices, curves, radix utilities, and constants.
  • Utilities: modification tracking helpers and structured error types.

Documentation can be found here.


Getting started

Add dartora to your project:

dart pub add dartora

Then import what you need:

import 'package:dartora/dartora.dart';
// or narrowly:
import 'package:dartora/collections.dart';
import 'package:dartora/search.dart';
import 'package:dartora/math.dart';
import 'package:dartora/util.dart';

Features

Collections

We added many different types of collections in.

  • Iteration primitives: IterationConstruct<E>, Iteration<E>, IterationBase<E>, IterationMap<K, V>.
  • Iteration defined: IterationItem<E>, IterationList<E>, IterationHolder<E>, IterationItemMap<K, V>.
  • Iterators: IteratorBuild<E>, IndexBaseIterator<E>, HolderIterator<E>.
  • Lists: MultiViewList<E>, LargeList<E>, IterableItems<E>.
  • Maps: OrderedMap<K,V> – insertion‑ordered map with stable key order.

ordered map & multi‑view list

import 'package:dartora/collections.dart';

final omap = OrderedMap<String, int>(map: {});
omap['b'] = 2;
omap['a'] = 1;
// Keeps insertion order across keys & iteration
for (final k in omap.keys) {
  print('$k → ${omap[k]}');
}

MultiViewList and LargeList help you present slices/views over large datasets without copying.

We added a way to build out simple search systems.

  • Model: Searchable, Tags, Tag<E>.
  • Engine: Search, SearchQuery, QueryEngine, QueryBuilder, PatternItem, SearchQueryComparison, SearchItem.

tags, required/forbidden, wildcard

import 'package:dartora/search.dart';

// Minimal Searchable using the factory
final items = [
  Searchable.build(
    id: '1', name: 'Red Apple', type: SearchableType.child,
    title: 'Apple', description: 'A sweet red fruit',
    tags: Tags([
      Tag<bool>('red', true),
      Tag<String>('category', 'fruit'),
    ]),
  ),
  Searchable.build(
    id: '2', name: 'Green Kale', type: SearchableType.child,
    title: 'Kale', description: 'Leafy and bitter',
    tags: Tags([
      Tag<bool>('green', true),
      Tag<String>('category', 'vegetable'),
    ]),
  ),
];

// Build a query from a human string
final search = Search.from('"sweet" -bitter #red app*');
final results = search.search(held: items);
for (final si in results) {
  print('${si.item.title}: ${si.comparison.points.total}');
}

Default query syntax (via QueryEngine.defaultEngine):

Token Meaning Notes
"..." Collector; marks a required phrase e.g. "sweet fruit" must appear
- Forbidden word/phrase e.g. -bitter
# Tag search e.g. #red or #category
* Wildcard e.g. app*apple, application, ...
\ Escape next special token e.g. \#literal
space Splits terms terms are scored individually

The engine produces a SearchQuery with optional, required, cannot and tag groups, and computes a SearchQueryComparison with a Points score. Use Search.validityCheck/itemCheck to filter invalid hits.

Math

We added several new mathematical computations in.

  • Basic: round(...) + RoundMode, root, log helpers, comparison utilities.
  • Advanced: Points (scoring), Matrix, curves, BaseRadix, Points collection helpers.
  • Constants: common numeric constants.

deterministic rounding

import 'package:dartora/math.dart';

final a = round(2.34567, decimals: 2);                // 2.35 (default: halfUp)
final b = round(2.5, mode: RoundMode.halfEven);       // 2.0 → banker's rounding
final c = round(-3.5, mode: RoundMode.halfAwayFrom);  // -4.0 → away from zero

Available modes (see RoundMode): halfUp, halfEven, halfOdd, halfAwayFrom, halfToZero, awayFrom, alwaysToZero.

Util

This part of the package is really simple, it has the utilities that were built because of this package.

  • Modification tracking: ModificationListener, ModLevel, ModificationAction.
  • Errors: BaseException, TypeException, KeyException with helpful messages.

Usage

Custom search syntax

For search, you can customize the parser by supplying your own QueryEngine(patternItems: [...]).

final engine = QueryEngine(patternItems: const [
  PatternItem.ignore,     // \
  PatternItem.hold,       // "..."
  PatternItem.space,      // space
  PatternItem.cannotHave, // -
  PatternItem.tag,        // #
  PatternItem.wild,       // *
]);
final query = SearchQuery.from('ice -hot #dessert', engine: engine);

Custom rounding mode

RoundMode is fully configurable: you can construct custom modes (even/odd/zero/away, thresholds, reversal, etc.).

const bankerTowardZero = RoundMode(
  roundAt: 5,
  reverse: false,
  toEven: true,
  toOdd: false,
  toZero: true,
  awayFromZero: false,
  allowSubtract: false,
);
final v = round(12.55, decimals: 1, mode: bankerTowardZero);

Additional information

Contributing

  • Open issues/PRs with reproducible cases.
  • Keep public APIs documented; prefer small, composable utilities.
  • Tests are appreciated for edge cases.

License

Licensed under the Apache License, Version 2.0.

Libraries

collections
dartora
Support for doing something awesome.
math
util