KodiScript Dart SDK

pub package Release

A lightweight, embeddable scripting language interpreter for Dart/Flutter applications.

📖 Documentation complète : docs-kodiscript.dickode.net

Installation

Add to your pubspec.yaml:

dependencies:
  kodi_script: ^0.4.0

Quick Start

import 'package:kodi_script/kodi_script.dart';

void main() {
  // Simple evaluation
  final result = KodiScript.eval('2 + 3 * 4');
  print(result); // 14.0

  // With variables
  final greeting = KodiScript.run(
    'greeting + ", " + name + "!"',
    variables: {'greeting': 'Hello', 'name': 'World'},
  );
  print(greeting.value); // "Hello, World!"

  // Capture output
  final output = KodiScript.run('''
    let items = ["apple", "banana", "cherry"]
    for (item in items) {
      print(item)
    }
  ''');
  print(output.output); // ["apple", "banana", "cherry"]
}

Features

  • Variables: let x = 10
  • Functions: fn(a, b) { return a + b }
  • Control Flow: if, else, for-in
  • Data Types: numbers, strings, booleans, arrays, objects
  • Null Safety: ?. (safe access), ?: (elvis operator)
  • 48+ Native Functions: string, math, random, type, array, JSON, encoding, crypto

🔌 Extensibilité

KodiScript est conçu pour être extensible. Vous pouvez enrichir le langage en ajoutant vos propres fonctions natives.

Fonctions personnalisées

final result = KodiScript.builder('greet("Dart")')
    .registerFunction('greet', (args) => 'Hello, ${args[0]}!')
    .execute();

print(result.value); // "Hello, Dart!"

Exemple : intégration Flutter

class ScriptEngine {
  final UserRepository userRepo;
  final NotificationService notifications;
  
  ScriptEngine(this.userRepo, this.notifications);
  
  Future<ScriptResult> execute(String script, Map<String, dynamic> context) {
    return KodiScript.builder(script)
      .withVariables(context)
      .registerFunction('fetchUser', (args) async {
        return await userRepo.findById(args[0] as int);
      })
      .registerFunction('sendPush', (args) {
        notifications.send(
          title: args[0] as String,
          body: args[1] as String,
        );
        return true;
      })
      .registerFunction('calculatePrice', (args) {
        final quantity = args[0] as num;
        final unitPrice = args[1] as num;
        final discount = args.length > 2 ? args[2] as num : 0;
        return quantity * unitPrice * (1 - discount / 100);
      })
      .execute();
  }
}

Cela permet à vos utilisateurs d'écrire des scripts puissants tout en gardant le contrôle sur les fonctionnalités exposées.

API Reference

KodiScript.eval(source)

Evaluates a script and returns the result value.

KodiScript.run(source, {variables})

Runs a script with optional variables and returns ScriptResult.

KodiScript.builder(source)

Creates a builder for advanced configuration.

Native Functions

Category Functions
String toString, toNumber, length, substring, toUpperCase, toLowerCase, trim, split, join, replace, contains, startsWith, endsWith, indexOf
Math abs, floor, ceil, round, min, max, pow, sqrt, sin, cos, tan, log, log10, exp
Random random, randomInt, randomUUID
Type typeOf, isNull, isNumber, isString, isBool
Array size, first, last, reverse, slice, sort, chunk, compact, pluck, zip, fromEntries, difference, intersection, union
JSON jsonParse, jsonStringify
Encoding base64Encode, base64Decode, urlEncode, urlDecode
Crypto md5, sha1, sha256
Date/Time see below

Array utilities

A null list argument behaves as an empty list; any other value that is not a list raises. Every function returns a new list or object and leaves its arguments untouched. All of them also work as methods: items.pluck("name").

Function Result
chunk(list, size) Consecutive lists of size elements, the last one possibly shorter. size below 1 raises
compact(list) The list without its null elements
pluck(list, path) The value at path for each element
zip(list1, list2, …) [[a0, b0, …], [a1, b1, …], …], as long as the shortest list
fromEntries(pairs) Object built from [[key, value], …]; a later pair wins
difference(a, b) Elements of a not in b, duplicates of a kept
intersection(a, b) Elements of a also in b, first occurrence only
union(list1, list2, …) Every element of every list, first occurrence only

A path is a string of segments separated by .: an object key, or a zero-based list index written in digits ("client.addresses.0.city"). A missing step gives null; "" designates the element itself.

Two values are equal when they have the same typeOf and the same canonical text, so 1 equals 1.0 but not "1", and {a: 1, b: 2} equals {b: 2, a: 1}.

Grouping and aggregation

These are interpreter builtins (like map and filter). The key is either a path string or a function fn(item, index); anything else raises. The group key of a value is its canonical text (null gives "null").

Function Result
groupBy(list, key) {groupKey: [items…]}, items in list order
countBy(list, key) {groupKey: count}
indexBy(list, key) {groupKey: item}, the last item of a key wins
uniqueBy(list, key) The first item of each distinct key
sumBy(list, key) Sum of the keys; null keys are skipped, a non-number key raises, empty gives 0
minBy(list, key), maxBy(list, key) The item with the smallest / largest key; null keys are skipped, the first wins on ties, null when nothing is left
partition(list, key) [[items whose key is truthy], [the others]]

Dates

A date argument is either a number of milliseconds since 1970-01-01T00:00:00Z (fraction truncated toward zero) or ISO-8601 text: 2026-10-19, 2026-10-19T08:30, 2026-10-19T08:30:00.250Z, 2026-10-19 08:30:00+01:00. Without a zone the time is UTC. Fields are validated (2026-02-29 is not a date). A date that cannot be read (null, an unreadable string, a boolean, a list, an object) makes a date function return null; it never raises. A wrong non-date argument, such as a count that is not a number, still raises.

Every calendar computation is done in UTC, whatever the host's time zone. A function that produces a date returns milliseconds; use toISO or formatDate to render it.

Function Result
now() Current instant, in ms
date(), time(), datetime() Current UTC date YYYY-MM-DD, time HH:mm:ss, instant (same as toISO(now()))
timestamp([date]) The date in ms (now without argument)
isDate(value) true if the value reads as a date
toISO(date) YYYY-MM-DDTHH:mm:ss.SSSZ
formatDate(date, [format]) Format with the tokens below (default YYYY-MM-DD)
parseDate(text, format) ms, or null: each token reads exactly its width in digits, literals must match, the whole text must be consumed. Missing fields default to 1970, month 1, day 1, 00:00:00.000
year, month, day, hour, minute, second ([date]) Calendar field (now without argument)
dayOfWeek([date]) 0 = Sunday … 6 = Saturday
daysInMonth(date) 28 to 31
isWeekend(date) true on Saturday or Sunday
addDays, addHours, addMinutes, addSeconds (date, n) Shifted date, in ms; n is truncated toward zero
addMonths(date, n), addYears(date, n) Calendar shift; a day missing from the target month becomes its last day (2026-01-31 + 1 month is 2026-02-28)
diffDays, diffHours, diffMinutes (a, b) Whole units from a to b, truncated toward zero (negative when b is before a)
diffMonths(a, b), diffYears(a, b) Whole calendar months / years from a to b
age(birth, [at]) Completed years; at defaults to now
startOfDay, endOfDay, startOfMonth, endOfMonth (date) Bounds of the period, in ms (endOf… is 23:59:59.999)

Format tokens, longest first at each position; any other character is copied (formatting) or must match exactly (parsing):

Token Meaning
YYYY 4-digit year
YY Last 2 digits of the year (formatting only; read as literal text when parsing)
MM Month 01–12
DD Day 01–31
HH Hour 00–23
mm Minute 00–59
ss Second 00–59
SSS Millisecond 000–999

Other Implementations

Language Package
Kotlin Maven Central
Go pkg.go.dev
TypeScript npm

License

MIT

Libraries

kodi_script
KodiScript - A lightweight, embeddable scripting language for Dart.